#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
use core::{
alloc::Layout,
future::Future,
};
struct LocalSpawnerVtable {
spawn_dyn: fn(handle: *const (), future_layout: Layout) -> SpawnCompleter,
finish_spawn: fn(handle: *const (), task_ptr_as_dyn_future: *mut dyn Future<Output = ()>);
on_clone: fn(handle: *const ()),
on_drop: fn(handle: *const ()),
}
impl LocalSpawnerVtable {
fn get<T: IntoLocalSpawner>() -> &'static Self {
&LocalSpawnerVtable {
spawn_dyn: T::spawn_dyn,
spawn_dyn: T::spawn_dyn,
on_clone: T::on_clone,
on_drop: T::on_drop,
}
}
}
pub struct LocalSpawner {
handle: *const (),
vtable: &'static LocalSpawnerVtable,
}
impl LocalSpawner {
#[cfg(feature = "alloc")]
pub fn new<T: IntoLocalSpawner>(inner: T) -> Self {
Self {
handle: T::into_raw(inner),
vtable: LocalSpawnerVtable::get::<T>(),
}
}
pub fn spawn<F: Future<Output = ()> + 'static>(&self, f: F) {
let spawn_completer = (self.vtable.spawn_dyn)(self.handle, Layout::new::<F>());
unsafe {
spawn_completer.spawn(f);
}
}
}
impl Clone for LocalSpawner {
fn clone(&self) -> Self {
(self.vtable.on_clone)(self.handle);
Self {
handle: self.handle,
vtable: self.vtable,
}
}
}
impl Drop for LocalSpawner {
fn drop(&mut self) {
(self.vtable.on_drop)(self.handle);
}
}
pub unsafe trait IntoLocalSpawner {
fn into_raw(self) -> *const ();
fn spawn_dyn(handle: *const (), future_layout: Layout) -> SpawnCompleter;
fn on_clone(handle: *const ());
fn on_drop(handle: *const ());
}
#[cfg(feature = "alloc")]
unsafe impl<T: LocalSpawnDyn> IntoLocalSpawner for Rc<T> {
fn into_raw(self) -> *const () {
Rc::into_raw(self) as *const ()
}
fn spawn_dyn<'a>(handle: *const (), future_layout: Layout) -> SpawnCompleter {
let spawner: &T = &*(handle as *const T);
LocalSpawnDyn::spawn_dyn(spawner, future_layout)
}
fn on_clone(handle: *const ()) {
Rc::increment_strong_count(handle as *const T);
}
fn on_drop(handle: *const ()) {
drop(Rc::from_raw(handle as *const T));
}
}
pub trait LocalSpawnDyn {
fn spawn_dyn(&self, future_layout: Layout) -> SpawnCompleter;
unsafe fn finish_spawn(&self, task_ptr_as_dyn_future: *mut dyn Future<Output = ()>);
}
pub struct SpawnCompleter {
handle: *const (),
vtable: &'static LocalSpawnerVtable,
task_ptr: *mut (),
future_ptr: *mut (),
}
impl SpawnCompleter {
pub fn new(spawner: &LocalSpawner, task_ptr: *mut (), future_ptr: *mut ()) -> Self {
Self {
handle: spawner.handle,
vtable: spawner.vtable,
task_ptr,
future_ptr,
}
}
unsafe fn spawn<F: Future<Output = ()> + 'static>(self, f: F) {
core::ptr::write(self.future_ptr as *mut F, f);
self.spawner.finish_spawn(self.task_ptr as *mut F as *mut dyn Future<Output = ()>);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}