#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
use core::{
alloc::Layout,
future::Future,
};
pub type LocalSpawnDynPtr = *const (dyn LocalSpawnDyn + 'static);
pub struct LocalSpawner {
spawner: LocalSpawnDynPtr,
clone_fn: fn(spawner: LocalSpawnDynPtr),
drop_fn: fn(spawner: LocalSpawnDynPtr),
}
impl LocalSpawner {
#[cfg(feature = "alloc")]
pub fn rc(inner: impl LocalSpawnDyn + 'static) -> Self {
Self::from(Rc::new(inner) as Rc<dyn LocalSpawnDyn + 'static>)
}
pub fn spawn<F: Future<Output = ()> + 'static>(&self, f: F) {
let spawner = unsafe { &*self.spawner };
let spawn_completer = spawner.spawn_dyn(Layout::new::<F>());
unsafe {
spawn_completer.spawn(f);
}
}
pub unsafe fn from_raw_parts(
spawner: LocalSpawnDynPtr,
clone_fn: fn(spawner: LocalSpawnDynPtr),
drop_fn: fn(spawner: LocalSpawnDynPtr),
) -> Self {
Self { spawner, clone_fn, drop_fn }
}
}
impl Clone for LocalSpawner {
fn clone(&self) -> Self {
(self.clone_fn)(self.spawner);
Self {
spawner: self.spawner,
clone_fn: self.clone_fn,
drop_fn: self.drop_fn,
}
}
}
impl Drop for LocalSpawner {
fn drop(&mut self) {
(self.drop_fn)(self.spawner);
}
}
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<'a> {
pub spawner: &'a dyn LocalSpawnDyn,
pub task_ptr: *mut (),
pub future_ptr: *mut (),
}
impl SpawnCompleter<'_> {
pub 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(feature = "alloc")]
impl From<Rc<dyn LocalSpawnDyn>> for LocalSpawner {
fn from(spawner: Rc<dyn LocalSpawnDyn>) -> Self {
unsafe {
Self::from_raw_parts(
Rc::into_raw(spawner),
|spawner_ptr| Rc::increment_strong_count(spawner_ptr),
|spawner_ptr| {
drop(Rc::from_raw(spawner_ptr));
},
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}