Skip to main content

sark_core/duplex/
admit.rs

1//! Affine carrier admission proofs for one duplex turn.
2use core::marker;
3
4use o3::{
5    base::marker::ThreadBound,
6    buffer::{resident, segments},
7};
8
9use crate::duplex::machine;
10
11type Owner<'turn, D> = marker::PhantomData<(
12    D,
13    ThreadBound,
14    fn(D) -> D,
15    fn(&'turn mut ()) -> &'turn mut (),
16)>;
17
18/// Session output and terminal state bound to one machine turn.
19#[must_use = "classify this emitted duplex turn"]
20pub struct Emission<'turn, 'd, D> {
21    pub(in crate::duplex) payload: Payload<'turn, 'd, D>,
22    pub(in crate::duplex) end: machine::End,
23    pub(in crate::duplex) after: machine::After,
24}
25
26impl<'turn, 'd, D> Emission<'turn, 'd, D> {
27    pub fn into_parts(self) -> (Payload<'turn, 'd, D>, machine::End, machine::After) {
28        (self.payload, self.end, self.after)
29    }
30}
31
32/// Exact ownership state of the session output for this turn.
33#[must_use = "consume the payload and its admission permission"]
34pub enum Payload<'turn, 'd, D> {
35    Present {
36        output: segments::Nonempty<resident::Shared<'d>>,
37        permit: Permit<'turn, Present, D>,
38    },
39    Vacant(Permit<'turn, Vacant, D>),
40}
41
42/// Proof that this turn owns an output chunk.
43pub enum Present {}
44
45/// Proof that this turn has no output chunk.
46pub enum Vacant {}
47
48/// Affine permission to classify one carrier admission attempt.
49#[must_use = "classify this carrier admission attempt"]
50pub struct Permit<'turn, M, D> {
51    pub(in crate::duplex) owner: Owner<'turn, D>,
52    pub(in crate::duplex) mode: marker::PhantomData<M>,
53}
54
55impl<'turn, M, D> Permit<'turn, M, D> {
56    pub fn commit<'d, R, E>(self, receipt: R) -> Admission<'turn, 'd, D, R, E> {
57        Admission::new(self.owner, Decision::Committed { receipt })
58    }
59}
60
61impl<'turn, D> Permit<'turn, Present, D> {
62    pub fn pending<'d, R, E>(
63        self,
64        rest: segments::Nonempty<resident::Shared<'d>>,
65        receipt: R,
66    ) -> Admission<'turn, 'd, D, R, E> {
67        Admission::new(
68            self.owner,
69            Decision::Pending {
70                remainder: rest,
71                receipt,
72            },
73        )
74    }
75
76    pub fn returned<'d, R, E>(
77        self,
78        error: E,
79        rest: segments::Nonempty<resident::Shared<'d>>,
80    ) -> Admission<'turn, 'd, D, R, E> {
81        Admission::new(
82            self.owner,
83            Decision::Returned {
84                error,
85                remainder: rest,
86            },
87        )
88    }
89}
90
91impl<'turn, D> Permit<'turn, Vacant, D> {
92    pub fn blocked<'d, R, E>(self, receipt: R) -> Admission<'turn, 'd, D, R, E> {
93        Admission::new(self.owner, Decision::Blocked { receipt })
94    }
95
96    pub fn reject<'d, R, E>(self, error: E) -> Admission<'turn, 'd, D, R, E> {
97        Admission::new(self.owner, Decision::Rejected { error })
98    }
99}
100
101/// Exact carrier disposition joined to its originating machine turn.
102#[must_use = "return this disposition to the duplex machine"]
103#[repr(transparent)]
104pub struct Admission<'turn, 'd, D, R, E> {
105    pub(in crate::duplex) decision: Decision<'d, R, E>,
106    pub(in crate::duplex) owner: Owner<'turn, D>,
107}
108
109impl<'turn, 'd, D, R, E> Admission<'turn, 'd, D, R, E> {
110    fn new(owner: Owner<'turn, D>, decision: Decision<'d, R, E>) -> Self {
111        Self { decision, owner }
112    }
113}
114
115pub(in crate::duplex) enum Decision<'d, R, E> {
116    Committed {
117        receipt: R,
118    },
119    Pending {
120        remainder: segments::Nonempty<resident::Shared<'d>>,
121        receipt: R,
122    },
123    Blocked {
124        receipt: R,
125    },
126    Rejected {
127        error: E,
128    },
129    Returned {
130        error: E,
131        remainder: segments::Nonempty<resident::Shared<'d>>,
132    },
133}
134
135const _: () = {
136    assert!(core::mem::size_of::<Permit<'static, Present, crate::duplex::Never>>() == 0);
137    assert!(core::mem::align_of::<Permit<'static, Present, crate::duplex::Never>>() == 1);
138    assert!(
139        core::mem::size_of::<Payload<'static, 'static, crate::duplex::Never>>()
140            == core::mem::size_of::<Option<segments::Nonempty<resident::Shared<'static>>>>()
141    );
142    assert!(
143        core::mem::align_of::<Payload<'static, 'static, crate::duplex::Never>>()
144            == core::mem::align_of::<Option<segments::Nonempty<resident::Shared<'static>>>>()
145    );
146    assert!(
147        core::mem::size_of::<Admission<'static, 'static, crate::duplex::Never, usize, usize>>()
148            == core::mem::size_of::<Decision<'static, usize, usize>>()
149    );
150    assert!(
151        core::mem::align_of::<Admission<'static, 'static, crate::duplex::Never, usize, usize>>()
152            == core::mem::align_of::<Decision<'static, usize, usize>>()
153    );
154};