1pub mod attach;
4pub mod outcome;
5
6use std::{mem, pin, task};
7
8use o3::{base::cell::region, depot};
9
10use crate::{
11 abi, context,
12 reply::{
13 self, Lane,
14 arena::{retire::Retired, state},
15 order,
16 usage::Footprint,
17 },
18};
19
20#[derive(Clone, Copy, Eq, PartialEq)]
22#[repr(u8)]
23pub enum Acceptance {
24 Payload,
26 Unit,
28 Collected,
30 First,
32}
33
34const _: () = {
35 assert!(mem::size_of::<Acceptance>() == mem::size_of::<bool>());
36 assert!(mem::size_of::<Option<Acceptance>>() == mem::size_of::<Acceptance>());
37};
38
39pub trait Extract<'s, 'arena, 'credits, 'region, D: Footprint, E = D> {
41 type Context: Unpin;
42 type Output;
43 const ACCEPTANCE: Acceptance = Acceptance::Payload;
44
45 fn extract(
46 context: &Self::Context,
47 slot: &mut reply::Slot<'_, 's, 'arena, 'credits, 'region, D, E>,
48 ) -> Option<Self::Output>;
49}
50
51struct Registration<'s, 'arena, 'credits, 'region, D: Footprint, E, K> {
52 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
53 key: state::EntryKey,
54}
55
56impl<'s, 'arena, 'credits, 'region, D: Footprint, E, K>
57 Registration<'s, 'arena, 'credits, 'region, D, E, K>
58{
59 fn live(
60 &self,
61 ) -> state::Registered<'s, reply::Arena<'arena, 'credits, 'region, D, E, K>, &Self> {
62 unsafe { depot::raw::Proof::new((self.lane.arena, self.key)) }
64 }
65}
66
67impl<D: Footprint, E, K> Drop for Registration<'_, '_, '_, '_, D, E, K> {
68 fn drop(&mut self) {
69 self.lane.defer_retire(Retired::new(self.key.index()));
70 }
71}
72
73struct Handle<'s, 'arena, 'credits, 'region, D: Footprint, E, K> {
74 reg: Option<Registration<'s, 'arena, 'credits, 'region, D, E, K>>,
75}
76
77impl<'s, 'arena, 'credits, 'region, D: Footprint, E, K>
78 Handle<'s, 'arena, 'credits, 'region, D, E, K>
79{
80 const fn new() -> Self {
81 Self { reg: None }
82 }
83
84 fn register(
85 &self,
86 token: &mut region::Token<region::Identity<'region>>,
87 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
88 accept: Acceptance,
89 tag: K,
90 ) -> Result<Registration<'s, 'arena, 'credits, 'region, D, E, K>, attach::Error> {
91 self.check(lane)?;
92 let key = lane.register(token, accept, tag)?;
93 Ok(Registration { lane, key })
94 }
95
96 fn check(
97 &self,
98 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
99 ) -> Result<(), attach::Error> {
100 if let Some(current) = self.reg.as_ref() {
101 return Err(attach::Error::Attached {
102 current: current.lane.index,
103 requested: lane.index,
104 });
105 }
106 Ok(())
107 }
108
109 fn try_ordered(
110 &mut self,
111 token: &mut region::Token<region::Identity<'region>>,
112 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
113 accept: Acceptance,
114 tag: K,
115 ) -> Result<order::Depth, attach::Error> {
116 let reg = self.register(token, lane, accept, tag)?;
117 let depth = reg.lane.depth(token);
118 self.reg = Some(reg);
119 Ok(depth)
120 }
121
122 fn try_attach(
123 &mut self,
124 token: &mut region::Token<region::Identity<'region>>,
125 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
126 accept: Acceptance,
127 tag: K,
128 ) -> Result<(), attach::Error> {
129 let reg = self.register(token, lane, accept, tag)?;
130 self.reg = Some(reg);
131 Ok(())
132 }
133
134 fn poll<O>(
135 &self,
136 mut context: pin::Pin<&mut context::Context<'_, 'region>>,
137 extract: impl FnOnce(
138 Option<&mut reply::Slot<'_, 's, 'arena, 'credits, 'region, D, E>>,
139 ) -> task::Poll<O>,
140 ) -> task::Poll<O> {
141 let wake = context.as_ref().waker();
142 let Some((mut slot, signal)) = self.slot(context.as_mut().region_token()) else {
143 return extract(None);
144 };
145 let output = extract(Some(&mut slot));
146 if output.is_pending() {
147 signal.register(wake.completion());
148 }
149 output
150 }
151
152 fn slot<'a>(
153 &'a self,
154 token: &'a mut region::Token<region::Identity<'region>>,
155 ) -> Option<(
156 reply::Slot<'a, 's, 'arena, 'credits, 'region, D, E>,
157 &'a mut state::Signal<'region>,
158 )>
159 where
160 's: 'a,
161 {
162 let reg = self.reg.as_ref()?;
163 reply::Arena::slot(token, reg.live())
164 }
165
166 fn detach(&mut self) {
167 self.reg = None;
168 }
169
170 fn detach_order(&mut self, token: ®ion::Token<region::Identity<'region>>) -> order::State {
171 let Some(reg) = self.reg.as_ref() else {
172 return order::State::Detached;
173 };
174 let order = reply::Arena::registered_order(token, reg.live());
175 self.detach();
176 order
177 }
178}
179
180pub struct Response<
181 's,
182 'arena,
183 'credits,
184 'region,
185 D: Footprint,
186 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
187 E = D,
188 K = (),
189> {
190 handle: Handle<'s, 'arena, 'credits, 'region, D, E, K>,
191 extract: X::Context,
192}
193
194impl<
195 's,
196 'arena,
197 'credits,
198 'region,
199 D: Footprint,
200 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
201 E,
202 K,
203> Response<'s, 'arena, 'credits, 'region, D, X, E, K>
204{
205 pub fn try_with<I, R>(
207 token: &mut region::Token<region::Identity<'region>>,
208 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
209 tag: K,
210 input: I,
211 make: impl FnOnce(I) -> (X::Context, R),
212 ) -> Result<(order::Depth, Self, R), (attach::Error, I)> {
213 let key = match lane.register(token, X::ACCEPTANCE, tag) {
214 Ok(key) => key,
215 Err(cause) => return Err((cause, input)),
216 };
217 let (extract, output) = make(input);
218 let response = Self {
219 handle: Handle {
220 reg: Some(Registration { lane, key }),
221 },
222 extract,
223 };
224 Ok((lane.depth(token), response, output))
225 }
226
227 pub fn try_group_by<I, Y, R, const N: usize>(
230 token: &mut region::Token<region::Identity<'region>>,
231 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
232 commands: &mut [Self; N],
233 terminal: &mut Response<'s, 'arena, 'credits, 'region, D, Y, E, K>,
234 input: I,
235 make: impl FnOnce(I) -> ([K; N], K, R),
236 ) -> Result<(order::Depth, R), (attach::Error, I)>
237 where
238 Y: Extract<'s, 'arena, 'credits, 'region, D, E>,
239 {
240 const { assert!(N > 0 && N < usize::MAX) };
241 for command in commands.iter() {
242 if let Err(cause) = command.handle.check(lane) {
243 return Err((cause, input));
244 }
245 }
246 if let Err(cause) = terminal.handle.check(lane) {
247 return Err((cause, input));
248 }
249 let (keys, key, output) =
250 lane.group_with(token, X::ACCEPTANCE, Y::ACCEPTANCE, input, make)?;
251 for (command, key) in commands.iter_mut().zip(keys) {
252 command.handle.reg = Some(Registration { lane, key });
253 }
254 terminal.handle.reg = Some(Registration { lane, key });
255 Ok((lane.depth(token), output))
256 }
257
258 pub const fn new() -> Self
259 where
260 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
261 {
262 Self::with(())
263 }
264
265 pub const fn with(extract: X::Context) -> Self {
266 Self {
267 handle: Handle::new(),
268 extract,
269 }
270 }
271
272 pub fn try_take(
275 &mut self,
276 token: &mut region::Token<region::Identity<'region>>,
277 ) -> Option<X::Output> {
278 let output = {
279 let (mut slot, _) = self.handle.slot(token)?;
280 X::extract(&self.extract, &mut slot)
281 };
282 if output.is_some() {
283 self.handle.detach();
284 }
285 output
286 }
287
288 pub fn poll_reply(
292 self: pin::Pin<&mut Self>,
293 context: pin::Pin<&mut context::Context<'_, 'region>>,
294 ) -> task::Poll<X::Output> {
295 let me = self.get_mut();
296 let output = me.handle.poll(context, |slot| {
297 slot.and_then(|slot| X::extract(&me.extract, slot))
298 .map_or(task::Poll::Pending, task::Poll::Ready)
299 });
300 if output.is_ready() {
301 me.handle.detach();
302 }
303 output
304 }
305
306 pub fn poll_next(
307 mut self: pin::Pin<&mut Self>,
308 context: pin::Pin<&mut context::Context<'_, 'region>>,
309 ) -> task::Poll<Option<X::Output>> {
310 let me = self.as_mut().get_mut();
311 let output = me.handle.poll(context, |slot| match slot {
312 Some(slot) => match X::extract(&me.extract, slot) {
313 Some(output) => task::Poll::Ready(Some(output)),
314 None if slot.state.is_finished() => task::Poll::Ready(None),
315 None => task::Poll::Pending,
316 },
317 None => task::Poll::Ready(None),
318 });
319 if matches!(output, task::Poll::Ready(None)) {
320 me.handle.detach();
321 }
322 output
323 }
324}
325
326impl<'s, 'arena, 'credits, 'region, D: Footprint, X, E, K> Default
327 for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
328where
329 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
330{
331 fn default() -> Self {
332 Self::new()
333 }
334}
335
336impl<
337 's,
338 'arena,
339 'credits,
340 'region,
341 D: Footprint,
342 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
343 E,
344 K,
345> attach::Attach<'s, 'arena, 'credits, 'region, D, E, K>
346 for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
347{
348 fn try_ordered(
349 &mut self,
350 token: &mut region::Token<region::Identity<'region>>,
351 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
352 tag: K,
353 ) -> Result<order::Depth, attach::Error> {
354 self.handle.try_ordered(token, lane, X::ACCEPTANCE, tag)
355 }
356
357 fn try_tagged(
358 &mut self,
359 token: &mut region::Token<region::Identity<'region>>,
360 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
361 tag: K,
362 ) -> Result<(), attach::Error> {
363 self.handle.try_attach(token, lane, X::ACCEPTANCE, tag)
364 }
365
366 fn detach(&mut self) {
367 self.handle.detach();
368 }
369
370 fn detach_order(&mut self, token: ®ion::Token<region::Identity<'region>>) -> order::State {
371 self.handle.detach_order(token)
372 }
373}
374
375impl<
376 's,
377 'arena,
378 'credits,
379 'region,
380 D: Footprint,
381 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
382 E,
383 K,
384> abi::Fiber<'region> for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
385{
386 type Output = X::Output;
387
388 fn poll(call: context::PollCall<'_, '_, 'region, Self>) -> task::Poll<X::Output> {
389 let (this, context) = call.into_parts();
390 this.poll_reply(context)
391 }
392}
393
394pub type Stream<'s, 'arena, 'credits, 'region, D, X, E = D, K = ()> =
395 Response<'s, 'arena, 'credits, 'region, D, X, E, K>;