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_group_by<I, Y, R, const N: usize>(
208 token: &mut region::Token<region::Identity<'region>>,
209 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
210 commands: &mut [Self; N],
211 terminal: &mut Response<'s, 'arena, 'credits, 'region, D, Y, E, K>,
212 input: I,
213 make: impl FnOnce(I) -> ([K; N], K, R),
214 ) -> Result<(order::Depth, R), (attach::Error, I)>
215 where
216 Y: Extract<'s, 'arena, 'credits, 'region, D, E>,
217 {
218 const { assert!(N > 0 && N < usize::MAX) };
219 for command in commands.iter() {
220 if let Err(cause) = command.handle.check(lane) {
221 return Err((cause, input));
222 }
223 }
224 if let Err(cause) = terminal.handle.check(lane) {
225 return Err((cause, input));
226 }
227 let (keys, key, output) =
228 lane.group_with(token, X::ACCEPTANCE, Y::ACCEPTANCE, input, make)?;
229 for (command, key) in commands.iter_mut().zip(keys) {
230 command.handle.reg = Some(Registration { lane, key });
231 }
232 terminal.handle.reg = Some(Registration { lane, key });
233 Ok((lane.depth(token), output))
234 }
235
236 pub const fn new() -> Self
237 where
238 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
239 {
240 Self::with(())
241 }
242
243 pub const fn with(extract: X::Context) -> Self {
244 Self {
245 handle: Handle::new(),
246 extract,
247 }
248 }
249
250 pub fn try_take(
253 &mut self,
254 token: &mut region::Token<region::Identity<'region>>,
255 ) -> Option<X::Output> {
256 let output = {
257 let (mut slot, _) = self.handle.slot(token)?;
258 X::extract(&self.extract, &mut slot)
259 };
260 if output.is_some() {
261 self.handle.detach();
262 }
263 output
264 }
265
266 pub fn poll_reply(
270 self: pin::Pin<&mut Self>,
271 context: pin::Pin<&mut context::Context<'_, 'region>>,
272 ) -> task::Poll<X::Output> {
273 let me = self.get_mut();
274 let output = me.handle.poll(context, |slot| {
275 slot.and_then(|slot| X::extract(&me.extract, slot))
276 .map_or(task::Poll::Pending, task::Poll::Ready)
277 });
278 if output.is_ready() {
279 me.handle.detach();
280 }
281 output
282 }
283}
284
285impl<'s, 'arena, 'credits, 'region, D: Footprint, X, E, K> Default
286 for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
287where
288 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
289{
290 fn default() -> Self {
291 Self::new()
292 }
293}
294
295impl<
296 's,
297 'arena,
298 'credits,
299 'region,
300 D: Footprint,
301 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
302 E,
303 K,
304> attach::Attach<'s, 'arena, 'credits, 'region, D, E, K>
305 for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
306{
307 fn try_ordered(
308 &mut self,
309 token: &mut region::Token<region::Identity<'region>>,
310 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
311 tag: K,
312 ) -> Result<order::Depth, attach::Error> {
313 self.handle.try_ordered(token, lane, X::ACCEPTANCE, tag)
314 }
315
316 fn try_tagged(
317 &mut self,
318 token: &mut region::Token<region::Identity<'region>>,
319 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
320 tag: K,
321 ) -> Result<(), attach::Error> {
322 self.handle.try_attach(token, lane, X::ACCEPTANCE, tag)
323 }
324
325 fn detach(&mut self) {
326 self.handle.detach();
327 }
328
329 fn detach_order(&mut self, token: ®ion::Token<region::Identity<'region>>) -> order::State {
330 self.handle.detach_order(token)
331 }
332}
333
334impl<
335 's,
336 'arena,
337 'credits,
338 'region,
339 D: Footprint,
340 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
341 E,
342 K,
343> abi::Fiber<'region> for Response<'s, 'arena, 'credits, 'region, D, X, E, K>
344{
345 type Output = X::Output;
346
347 fn poll(call: context::PollCall<'_, '_, 'region, Self>) -> task::Poll<X::Output> {
348 let (this, context) = call.into_parts();
349 this.poll_reply(context)
350 }
351}
352
353pub struct Stream<
354 's,
355 'arena,
356 'credits,
357 'region,
358 D: Footprint,
359 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
360 E = D,
361 K = (),
362> {
363 handle: Handle<'s, 'arena, 'credits, 'region, D, E, K>,
364 extract: X::Context,
365}
366
367impl<
368 's,
369 'arena,
370 'credits,
371 'region,
372 D: Footprint,
373 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
374 E,
375 K,
376> Stream<'s, 'arena, 'credits, 'region, D, X, E, K>
377{
378 pub const fn new() -> Self
379 where
380 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
381 {
382 Self::with(())
383 }
384
385 pub const fn with(extract: X::Context) -> Self {
386 Self {
387 handle: Handle::new(),
388 extract,
389 }
390 }
391
392 pub fn poll_next(
393 mut self: pin::Pin<&mut Self>,
394 context: pin::Pin<&mut context::Context<'_, 'region>>,
395 ) -> task::Poll<Option<X::Output>> {
396 let me = self.as_mut().get_mut();
397 let output = me.handle.poll(context, |slot| match slot {
398 Some(slot) => match X::extract(&me.extract, slot) {
399 Some(output) => task::Poll::Ready(Some(output)),
400 None if slot.state.is_finished() => task::Poll::Ready(None),
401 None => task::Poll::Pending,
402 },
403 None => task::Poll::Ready(None),
404 });
405 if matches!(output, task::Poll::Ready(None)) {
406 me.handle.detach();
407 }
408 output
409 }
410}
411
412impl<'s, 'arena, 'credits, 'region, D: Footprint, X, E, K> Default
413 for Stream<'s, 'arena, 'credits, 'region, D, X, E, K>
414where
415 X: Extract<'s, 'arena, 'credits, 'region, D, E, Context = ()>,
416{
417 fn default() -> Self {
418 Self::new()
419 }
420}
421
422impl<
423 's,
424 'arena,
425 'credits,
426 'region,
427 D: Footprint,
428 X: Extract<'s, 'arena, 'credits, 'region, D, E>,
429 E,
430 K,
431> attach::Attach<'s, 'arena, 'credits, 'region, D, E, K>
432 for Stream<'s, 'arena, 'credits, 'region, D, X, E, K>
433{
434 fn try_ordered(
435 &mut self,
436 token: &mut region::Token<region::Identity<'region>>,
437 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
438 tag: K,
439 ) -> Result<order::Depth, attach::Error> {
440 self.handle.try_ordered(token, lane, X::ACCEPTANCE, tag)
441 }
442
443 fn try_tagged(
444 &mut self,
445 token: &mut region::Token<region::Identity<'region>>,
446 lane: Lane<'s, 'arena, 'credits, 'region, D, E, K>,
447 tag: K,
448 ) -> Result<(), attach::Error> {
449 self.handle.try_attach(token, lane, X::ACCEPTANCE, tag)
450 }
451
452 fn detach(&mut self) {
453 self.handle.detach();
454 }
455
456 fn detach_order(&mut self, token: ®ion::Token<region::Identity<'region>>) -> order::State {
457 self.handle.detach_order(token)
458 }
459}