Sync/Async best practices

When async came out, I wanted to experiment with it a bit, trying to understand how it works (never worked with asynchronous code before). I was a bit surprised, when I found out, that Rust didn't include any way to "syncify" async code by resolving futures. I didn't want to use full-blown third-party crates for some simple experimentation, so I had to implement my own version. I looked at the available packages on crates.io, that dealt with this problem already and then went on to implement the code to resolve futures. It might be of interest to you, if you want to test performance of sync vs async. Here's my code to resolve a future in the simplest possible way (to my knowledge):

#![no_implicit_prelude]

use ::core::clone::Clone;
use ::core::future::Future;
use ::core::mem::transmute;
use ::core::mem::ManuallyDrop;
use ::core::pin::Pin;
use ::core::task::Context;
use ::core::task::Poll;
use ::core::task::RawWaker;
use ::core::task::RawWakerVTable;
use ::core::task::Waker;
use ::std::thread::current;
use ::std::thread::park;
use ::std::thread::Thread;

static VTABLE: RawWakerVTable = {
    /// 1. Convert the data from `*const ()` to `Thread`
    /// 2. Wrap the data with `ManuallyDrop`, because we don't own it
    /// 3. Clone the data
    /// 4. Convert the cloned data from `Thread` to `*const ()`
    /// 5. Create a new `RawWaker` instance with the cloned data and return it
    unsafe fn clone(data: *const ()) -> RawWaker {
        RawWaker::new(
            transmute(ManuallyDrop::new(transmute::<_, Thread>(data)).clone()),
            &VTABLE,
        )
    }

    /// 1. Convert the data from `*const ()` to `Thread`
    /// 2. Wake up the waiting thread
    /// 3. (Automatically) Drop the data, because we own it
    unsafe fn wake(data: *const ()) {
        transmute::<_, Thread>(data).unpark();
    }

    /// 1. Convert the data from `*const ()` to `Thread`
    /// 2. Wrap the data with `ManuallyDrop`, because we don't own it
    /// 3. Wake up the waiting thread
    unsafe fn wake_by_ref(data: *const ()) {
        ManuallyDrop::new(transmute::<_, Thread>(data)).unpark();
    }

    /// 1. Convert the data from `*const ()` to `Thread`
    /// 2. (Automatically) Drop the data, because we own it
    unsafe fn drop(data: *const ()) {
        transmute::<_, Thread>(data);
    }

    RawWakerVTable::new(clone, wake, wake_by_ref, drop)
};

pub trait FutureResolve: Future {
    fn resolve(self) -> Self::Output;
}

impl<TFuture> FutureResolve for TFuture
where
    TFuture: Future,
{
    fn resolve(mut self) -> Self::Output {
        let mut this = unsafe { Pin::new_unchecked(&mut self) };
        let raw_waker = RawWaker::new(unsafe { transmute(current()) }, &VTABLE);
        let waker = unsafe { Waker::from_raw(raw_waker) };
        let mut context = Context::from_waker(&waker);

        loop {
            // `async`-generated futures call clone and wake
            match this.as_mut().poll(&mut context) {
                Poll::Ready(result) => return result,
                Poll::Pending => park(),
            };
        }
    }
}

Note: Thread is just a wrapper around an Arc, that contains the actual Thread-data, which is why I used transmute. However, the standard library does currently not guarantee anything about the inner workings of Thread. Therefore, I'd never use transmute for this task in production. You'd have to wrap Thread in another Arc to be certain, that it'll work in all future versions of Rust.

P.S.: I learned, that async wasn't what I needed for what I'm doing, so I stopped the experiments pretty much right after finishing the resolve-method.