1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
//!Waker implementation using current thread token.
//!
//!This is useful to work with futures without actually employing runtime
//!
//!## Usage
//!
//!```rust
//!use core::{time, task};
//!use std::thread;
//!
//!use thread_waker::waker;
//!
//!fn my_future(waker: task::Waker) {
//! thread::sleep(time::Duration::from_millis(250));
//! waker.wake();
//!}
//!
//!let waker = waker(thread::current());
//!
//!for _ in 0..4 {
//! let waker = waker.clone();
//! thread::spawn(move || my_future(waker));
//! thread::park();
//!}
//!
//!println!("I'm done!");
//!```
#![warn(missing_docs)]
#![allow(clippy::style)]
// Dudue, do you think I'm retard not to know what I transmute?
#![allow(clippy::missing_transmute_annotations)]
use core::{task, mem};
use std::thread::Thread;
const VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(clone, wake, wake_by_ref, on_drop);
unsafe fn on_drop(thread: *const ()) {
let thread: Thread = mem::transmute(thread);
drop(thread);
}
unsafe fn clone(thread: *const()) -> task::RawWaker {
//Thread handle is just simple Arc pointer to cloning it is cheap and efficient
//but we need to make sure to forget current thread, otherwise it is no clone
//as Clone callback is done via reference
let thread: Thread = mem::transmute(thread);
let new_ptr = mem::transmute(thread.clone());
mem::forget(thread);
task::RawWaker::new(new_ptr, &VTABLE)
}
unsafe fn wake(thread: *const ()) {
let thread: Thread = mem::transmute(thread);
thread.unpark();
}
unsafe fn wake_by_ref(thread: *const ()) {
let thread: Thread = mem::transmute(thread);
thread.unpark();
//wake_by_ref should not consume self
mem::forget(thread);
}
#[inline(always)]
///Creates waker from thread handle
pub fn waker(thread: Thread) -> task::Waker {
unsafe {
task::Waker::from_raw(task::RawWaker::new(mem::transmute(thread), &VTABLE))
}
}