Add waker_fn (#18)
* Add waker_fn
* Add a waker_fn test
* Double sleep times
* More benches
* Prohibit recursive block_on calls
* Reformat code
diff --git a/src/waker_fn.rs b/src/waker_fn.rs
new file mode 100644
index 0000000..37105f1
--- /dev/null
+++ b/src/waker_fn.rs
@@ -0,0 +1,43 @@
+use alloc::sync::Arc;
+use core::mem::{self, ManuallyDrop};
+use core::task::{RawWaker, RawWakerVTable, Waker};
+
+/// Creates a waker from a wake function.
+///
+/// The function gets called every time the waker is woken.
+pub fn waker_fn<F: Fn() + Send + Sync + 'static>(f: F) -> Waker {
+ let raw = Arc::into_raw(Arc::new(f)) as *const ();
+ let vtable = &Helper::<F>::VTABLE;
+ unsafe { Waker::from_raw(RawWaker::new(raw, vtable)) }
+}
+
+struct Helper<F>(F);
+
+impl<F: Fn() + Send + Sync + 'static> Helper<F> {
+ const VTABLE: RawWakerVTable = RawWakerVTable::new(
+ Self::clone_waker,
+ Self::wake,
+ Self::wake_by_ref,
+ Self::drop_waker,
+ );
+
+ unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
+ let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
+ mem::forget(arc.clone());
+ RawWaker::new(ptr, &Self::VTABLE)
+ }
+
+ unsafe fn wake(ptr: *const ()) {
+ let arc = Arc::from_raw(ptr as *const F);
+ (arc)();
+ }
+
+ unsafe fn wake_by_ref(ptr: *const ()) {
+ let arc = ManuallyDrop::new(Arc::from_raw(ptr as *const F));
+ (arc)();
+ }
+
+ unsafe fn drop_waker(ptr: *const ()) {
+ drop(Arc::from_raw(ptr as *const F));
+ }
+}