Skip to main content

dope_fiber/abi/
mod.rs

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