till/
lib.rs

1#![no_std]
2#![feature(waker_getters)]
3
4pub mod impls;
5
6// static CURRENT_EXECUTOR: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
7
8struct BoundedEventSourceId(usize);
9
10use core::{
11    cell::RefCell, future::Future, hint::unreachable_unchecked, pin::Pin, sync::atomic::AtomicPtr,
12    usize,
13};
14
15use futures::future::FusedFuture;
16use impls::no_heap::SingleThreadMarshall;
17
18pub const fn raw_waker_v_table<Marshall: ExecutorMarshall>() -> core::task::RawWakerVTable {
19    unsafe fn clone<Marshall: ExecutorMarshall>(marshall: *const ()) -> core::task::RawWaker {
20        let waker = Marshall::waker(&*(marshall as *const Marshall));
21        let raw = waker.as_raw();
22        let raw = core::task::RawWaker::new(raw.data(), raw.vtable());
23        core::mem::forget(waker);
24        raw
25    }
26    unsafe fn wake<Marshall: ExecutorMarshall>(marshall: *const ()) {
27        // Nothing is owned or needs to be cleaned up so this is just wake_by_ref
28        wake_by_ref::<Marshall>(marshall)
29    }
30    unsafe fn wake_by_ref<Marshall: ExecutorMarshall>(marshall: *const ()) {
31        let marshall = &*(marshall as *const Marshall);
32        marshall.wake();
33    }
34    unsafe fn drop<Marshall: ExecutorMarshall>(_marshall: *const ()) {
35        // The marshall has static lifetime so no cleanup required
36    }
37    core::task::RawWakerVTable::new(
38        clone::<Marshall>,
39        wake::<Marshall>,
40        wake_by_ref::<Marshall>,
41        drop::<Marshall>,
42    )
43}
44
45// fn raw_waker<Marshall: ExecutorMarshall>(marshall: &'static Marshall) -> core::task::RawWaker {
46//     core::task::RawWaker::new(
47//         marshall as *const Marshall as *const (),
48//         Marshall::v_table(),
49//     )
50// }
51
52pub trait ExecutorMarshall: Sync + 'static {
53    fn wake(&'static self);
54    fn waker(&'static self) -> core::task::Waker;
55}
56
57pub struct Executor<'a, Tasks: TaskManager, Pool: EventSourcePool> {
58    tasks: &'a mut Tasks,
59    pool: &'a mut Pool,
60}
61
62pub enum WakeStatus {
63    Woken,
64    Asleep,
65}
66
67pub trait TaskManager {
68    type Marshall: ExecutorMarshall;
69    type TaskIterator<'a>: Iterator<
70        Item = (
71            Pin<&'a mut dyn FusedFutureWithWakeStatus<Output = ()>>,
72            &'static Self::Marshall,
73        ),
74    >
75    where
76        Self: 'a;
77    fn get_task(
78        &mut self,
79        i: usize,
80    ) -> Option<(
81        Pin<&mut dyn FusedFutureWithWakeStatus<Output = ()>>,
82        &'static Self::Marshall,
83    )>;
84    fn sleep_task(&mut self, i: usize);
85    fn sleep_all(&mut self);
86    fn tasks<'a>(&'a mut self) -> Self::TaskIterator<'a>;
87}
88
89pub trait EventSourcePool: Context {
90    type SourceIterator<'a>: Iterator<Item = &'a mut Source>
91    where
92        Self: 'a;
93
94    fn sources<'a>(&'a mut self) -> Self::SourceIterator<'a>;
95}
96
97pub trait Context {
98    type Id;
99    unsafe fn register_source(&self, source: *mut dyn EventSource) -> Option<Self::Id>;
100    fn unregister_source(&self, id: Self::Id);
101}
102
103struct BoundedEventSourcePool<const N: usize> {
104    slots: RefCell<[Option<*mut dyn EventSource>; N]>,
105}
106
107impl<const N: usize> Context for BoundedEventSourcePool<N> {
108    type Id = BoundedEventSourceId;
109
110    unsafe fn register_source(&self, source: *mut dyn EventSource) -> Option<Self::Id> {
111        let mut slots = self.slots.borrow_mut();
112        if let Some((i, empty_slot)) = slots
113            .iter_mut()
114            .enumerate()
115            .find(|(_, slot)| slot.is_none())
116        {
117            *empty_slot = Some(source);
118            Some(BoundedEventSourceId(i))
119        } else {
120            None
121        }
122    }
123
124    fn unregister_source(&self, id: Self::Id) {
125        self.slots.borrow_mut()[id.0] = None;
126    }
127}
128
129pub trait EventSource {
130    fn setup(&mut self);
131
132    fn check(&mut self);
133
134    fn cleanup(self);
135}
136
137pub trait FusedFutureWithWakeStatus: FusedFuture {
138    fn status(&self) -> WakeStatus;
139    fn set_status(self: Pin<&mut Self>, status: WakeStatus);
140}
141
142pub trait FusedFutureExt {
143    fn with_wake_status_st(self) -> SingleThreadWithWakeStatus<Self>
144    where
145        Self: Sized;
146}
147
148#[pin_project::pin_project]
149pub struct SingleThreadWithWakeStatus<F> {
150    #[pin]
151    f: F,
152    status: core::cell::Cell<bool>,
153}
154
155impl<F> SingleThreadWithWakeStatus<F> {
156    pub unsafe fn register(self: Pin<&mut Self>, marshall: &'static SingleThreadMarshall) {
157        let projection = self.project();
158        marshall.register(&projection.status);
159    }
160}
161
162impl<F: Future> Future for SingleThreadWithWakeStatus<F> {
163    type Output = F::Output;
164
165    fn poll(
166        self: Pin<&mut Self>,
167        cx: &mut core::task::Context<'_>,
168    ) -> core::task::Poll<Self::Output> {
169        let projection = self.project();
170        projection.f.poll(cx)
171    }
172}
173
174impl<F: FusedFuture> FusedFuture for SingleThreadWithWakeStatus<F> {
175    fn is_terminated(&self) -> bool {
176        self.f.is_terminated()
177    }
178}
179
180impl<F: FusedFuture> FusedFutureWithWakeStatus for SingleThreadWithWakeStatus<F> {
181    fn status(&self) -> WakeStatus {
182        if self.status.get() {
183            WakeStatus::Woken
184        } else {
185            WakeStatus::Asleep
186        }
187    }
188
189    fn set_status(self: Pin<&mut Self>, status: WakeStatus) {
190        match status {
191            WakeStatus::Woken => self.status.set(true),
192            WakeStatus::Asleep => self.status.set(false),
193        }
194    }
195}
196
197impl<F: futures::future::FusedFuture> FusedFutureExt for F {
198    fn with_wake_status_st(self) -> SingleThreadWithWakeStatus<Self> {
199        SingleThreadWithWakeStatus {
200            f: self,
201            status: core::cell::Cell::new(true),
202        }
203    }
204}
205
206pub enum Source {
207    Poll {},
208}
209
210impl<'a, Tasks: TaskManager, Pool: EventSourcePool> Executor<'a, Tasks, Pool> {
211    pub fn new(tasks: &'a mut Tasks, pool: &'a mut Pool) -> Self {
212        Executor { tasks, pool }
213    }
214
215    pub fn run_to_completion(self) {
216        while self.tasks.tasks().any(|(task, _)| !task.is_terminated()) {
217            for (i, (mut task, marshall)) in
218                self.tasks.tasks().enumerate().filter(|(_, (task, _))| {
219                    !task.is_terminated() && matches!(task.status(), WakeStatus::Woken)
220                })
221            {
222                let waker = marshall.waker();
223                let mut context: core::task::Context<'_> = core::task::Context::from_waker(&waker);
224                task.as_mut().set_status(WakeStatus::Asleep);
225                let _ = task.poll(&mut context);
226            }
227            // TODO - Process event source pool
228        }
229    }
230}