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