Skip to main content

dope_fiber/abi/
mod.rs

1pub mod future;
2mod join;
3pub mod machine;
4mod pending;
5mod pollfn;
6pub mod race;
7mod ready;
8mod task;
9
10use core::{pin, task::Poll};
11use o3::{
12    base::cell::region,
13    mem::{self, slot},
14};
15
16pub use join::Join;
17pub use pending::Pending;
18pub use pollfn::{PollFn, poll_fn};
19pub use ready::Ready;
20pub use task::Task;
21
22use crate::context;
23
24#[derive(Clone, Copy, Debug)]
25enum Side {
26    Left,
27    Right,
28}
29
30impl Side {
31    const fn other(self) -> Self {
32        match self {
33            Self::Left => Self::Right,
34            Self::Right => Self::Left,
35        }
36    }
37}
38
39#[must_use = "a fiber does nothing unless it is driven"]
40/// A pinned unit of cooperative work admitted by its live owner and driver.
41/// Ready ends that owner's polling authority; implementations do not duplicate it.
42/// [`Task`] retains standalone completion; nested polls share admission and budget.
43pub trait Fiber<'d>: Sized {
44    type Output;
45
46    fn poll(call: context::PollCall<'_, '_, 'd, Self>) -> Poll<Self::Output>;
47}
48
49/// A pinned sequence whose owner stops polling after `Ready(None)`.
50/// Each admitted call may yield one item while retaining the same stream owner.
51/// `PollCall` admits work; it does not track stream completion.
52/// [`Task`] releases the child at end and retains that terminal result.
53#[must_use = "a stream does nothing unless it is driven"]
54pub trait Stream<'d>: Sized {
55    type Item;
56
57    fn poll_next(call: context::PollCall<'_, '_, 'd, Self>) -> Poll<Option<Self::Item>>;
58}
59
60/// One admitted transition of a movable state in its exclusively owned slot.
61pub trait Resume<'d>: Sized + Unpin {
62    type Output;
63    type Ready;
64
65    fn poll<'slot, 'id>(
66        live: &mut Live<'slot, 'id, Self>,
67        admit: &mut context::Admission<'_, '_, 'd>,
68    ) -> Poll<Self::Ready>;
69
70    fn finish<'slot, 'id>(
71        live: Live<'slot, 'id, Self>,
72        ready: Self::Ready,
73        admit: context::Admission<'_, '_, 'd>,
74    ) -> Transition<'id, Self::Output>;
75}
76
77/// Owns a movable state until its consuming transition completes.
78#[repr(transparent)]
79#[must_use = "a task does nothing unless it is driven"]
80pub struct Owned<F> {
81    state: slot::Storage<F>,
82}
83
84impl<F> Owned<F> {
85    pub const fn new(value: F) -> Self {
86        Self {
87            state: slot::Storage::filled(value, ()),
88        }
89    }
90}
91
92/// Admitted exclusive access to the current state in one owned slot.
93pub struct Live<'slot, 'id, F> {
94    slot: mem::raw::Occupied<'slot, F>,
95    proof: region::Proof<region::Identity<'id>>,
96}
97
98impl<'slot, 'id, F> Live<'slot, 'id, F> {
99    pub fn get_mut(&mut self) -> &mut F {
100        self.slot.get_mut()
101    }
102
103    pub fn pending<O>(self) -> Transition<'id, O> {
104        Transition {
105            poll: Poll::Pending,
106            _proof: self.proof,
107        }
108    }
109
110    pub fn take(self) -> (Vacant<'slot, 'id, F>, F) {
111        let (value, slot) = self.slot.take();
112        (
113            Vacant {
114                slot,
115                proof: self.proof,
116            },
117            value,
118        )
119    }
120}
121
122/// The original slot after its state has been consumed.
123pub struct Vacant<'slot, 'id, F> {
124    slot: mem::raw::Vacant<'slot, F>,
125    proof: region::Proof<region::Identity<'id>>,
126}
127
128impl<'slot, 'id, F> Vacant<'slot, 'id, F> {
129    pub fn insert(self, value: F) -> Live<'slot, 'id, F> {
130        Live {
131            slot: self.slot.insert(value),
132            proof: self.proof,
133        }
134    }
135
136    pub fn complete<O>(self, output: O) -> Transition<'id, O> {
137        Transition {
138            poll: Poll::Ready(output),
139            _proof: self.proof,
140        }
141    }
142}
143
144/// A result issued only by the original live or emptied slot.
145pub struct Transition<'id, O> {
146    poll: Poll<O>,
147    _proof: region::Proof<region::Identity<'id>>,
148}
149
150impl<'d, F: Resume<'d>> Fiber<'d> for Owned<F> {
151    type Output = F::Output;
152
153    fn poll(call: context::PollCall<'_, '_, 'd, Self>) -> Poll<Self::Output> {
154        let (this, mut admit) = call.into_admit();
155        let Some(slot) = this.get_mut().state.occupied() else {
156            return Poll::Pending;
157        };
158        region::Token::scope(|token| {
159            let mut live = Live {
160                slot,
161                proof: token.proof(),
162            };
163            match F::poll(&mut live, &mut admit) {
164                Poll::Pending => live.pending(),
165                Poll::Ready(ready) => F::finish(live, ready, admit),
166            }
167            .poll
168        })
169    }
170}
171
172impl<'d, F: Fiber<'d>> Fiber<'d> for pin::Pin<&mut Task<F>> {
173    type Output = F::Output;
174
175    fn poll(call: context::PollCall<'_, '_, 'd, Self>) -> Poll<Self::Output> {
176        Task::<F>::poll(call.map(|fiber| fiber.get_mut().as_mut()))
177    }
178}