Skip to main content

sark_core/body/buffered/
mod.rs

1use crate::body::admit;
2type Transfer<T, E> = Result<T, mem::Rejected<T, Transition<E>>>;
3use o3::{buffer::segments, mem};
4
5use crate::{
6    body::{self, credit, flow, ingress, input, stream},
7    manifold::stream::Boundary,
8};
9
10mod loan;
11mod receive;
12mod rejected;
13mod store;
14
15pub use loan::Loan;
16pub use rejected::Rejected;
17pub use store::Store;
18
19/// Logical body state and its retained transport storage.
20#[derive(Debug)]
21pub struct State<S, O: credit::Origin = credit::raw::Stored> {
22    pub(in crate::body) state: ingress::State<O>,
23    pub(in crate::body) storage: Option<S>,
24}
25
26/// Exact failure of one buffered body-input transition.
27#[derive(Debug)]
28pub enum Error<E> {
29    Body(body::Error),
30    Retain(E),
31}
32
33/// Exact failure of buffered-to-stream ownership transfer.
34#[derive(Debug)]
35pub enum Transition<E> {
36    Body(body::Error),
37    Build(E),
38}
39
40/// Input ownership returned by one retention attempt.
41#[must_use = "retention must either consume or return the input owner"]
42pub enum Retain<S, D, E> {
43    Accepted {
44        storage: Option<S>,
45    },
46    Rejected {
47        storage: Option<S>,
48        input: D,
49        error: E,
50    },
51}
52
53/// Input ownership after one buffered body transition.
54#[must_use = "accepted discarded input still belongs to the caller"]
55pub enum Push<D, E> {
56    Accepted,
57    Discarded(D),
58    Rejected { input: D, error: Error<E> },
59}
60
61impl<S> State<S> {
62    pub fn new(open: admit::Track<admit::Open>) -> Self {
63        Self {
64            state: ingress::State::new(admit::Start::Open(open), credit::raw::Stored::new()),
65            storage: None,
66        }
67    }
68
69    pub fn finished(done: admit::Track<admit::Finished>) -> Self {
70        Self {
71            state: ingress::State::new(admit::Start::Finished(done), credit::raw::Stored::new()),
72            storage: None,
73        }
74    }
75}
76
77impl<S, O: credit::Origin> State<S, O> {
78    pub fn start(open: admit::Track<admit::Open>, ledger: &credit::raw::Ledger<'_, O>) -> Self {
79        Self {
80            state: ingress::State::new(admit::Start::Open(open), ledger.origin()),
81            storage: None,
82        }
83    }
84
85    pub fn ended(done: admit::Track<admit::Finished>, ledger: &credit::raw::Ledger<'_, O>) -> Self {
86        Self {
87            state: ingress::State::new(admit::Start::Finished(done), ledger.origin()),
88            storage: None,
89        }
90    }
91
92    pub const fn max_body(&self) -> usize {
93        self.state.max_body()
94    }
95
96    pub const fn retention(&self) -> admit::Retention {
97        self.state.retention()
98    }
99
100    pub const fn stream(&self) -> admit::Stream {
101        self.state.stream()
102    }
103
104    pub const fn len(&self) -> usize {
105        self.state.logical_len()
106    }
107
108    pub const fn is_empty(&self) -> bool {
109        self.state.logical_len() == 0
110    }
111
112    pub fn try_push<D, E, F, R>(
113        &mut self,
114        ledger: &mut credit::raw::Ledger<'_, O>,
115        event: E,
116        input: input::Input<D>,
117        rmax: credit::Limits,
118        cmax: credit::Limits,
119        retain: F,
120    ) -> Push<D, R>
121    where
122        E: credit::Evidence,
123        F: FnOnce(Option<S>, D) -> Retain<S, D, R>,
124    {
125        let turn = ingress::Turn::new(&mut self.state, ledger, event);
126        receive::Receive {
127            turn,
128            storage: &mut self.storage,
129        }
130        .try_push(input, rmax, cmax, retain)
131    }
132
133    /// Ends input with its final logical total, preserving storage and credit.
134    pub fn try_exact(mut self, len: usize) -> body::Transfer<Self, body::Error> {
135        if let Err(error) = self.state.try_exact(len) {
136            return body::Transfer::Rejected { build: self, error };
137        }
138        if let Err(error) = self.state.try_end() {
139            return body::Transfer::Rejected { build: self, error };
140        }
141        body::Transfer::Accepted(self)
142    }
143
144    pub fn try_finish<'d, E: credit::Evidence>(
145        self,
146        ledger: &mut credit::raw::Ledger<'_, O>,
147        event: &mut E,
148    ) -> Result<body::Body<S::Output>, Rejected<S, S::Output, O>>
149    where
150        S: Store<'d>,
151    {
152        let Self { state, storage } = self;
153        let (track, mut release) = match state.try_finish() {
154            Ok(finished) => finished,
155            Err(failure) => {
156                let (state, error) = failure.into_parts();
157                return Err(Rejected::Admission {
158                    state: Self { state, storage },
159                    error,
160                });
161            }
162        };
163        let source = S::finish(storage);
164        let body = match body::Body::try_new(track, source) {
165            Ok(body) => body,
166            Err(failure) => {
167                return Err(Rejected::Storage { failure, release });
168            }
169        };
170        let freed = match ledger.amount().try_drain(&mut release.amount) {
171            Ok(change) => change.commit(),
172            Err(error) => {
173                return Err(Rejected::Credit {
174                    body,
175                    release,
176                    error: body::Error::Credit(error),
177                });
178            }
179        };
180        event.released(freed, credit::Disposition::Admitted);
181        Ok(body)
182    }
183
184    pub fn discard<E: credit::Evidence>(
185        self,
186        ledger: &mut credit::raw::Ledger<'_, O>,
187        event: &mut E,
188    ) -> credit::Discard<O> {
189        self.into_release().try_discard(ledger, event)
190    }
191
192    pub fn abandon<E: credit::Evidence>(self, event: E) {
193        self.into_release().discard(event);
194    }
195
196    pub fn into_release(self) -> credit::Release<O> {
197        self.state.abandon()
198    }
199}
200
201impl<S, O: credit::Origin> State<S, O> {
202    /// Moves already-accounted retained input into an incremental builder.
203    /// The request state and its ledger charge remain the same capability;
204    /// neither bytes nor owners are copied or reserved a second time.
205    pub fn try_stream<'d, B, I, F>(
206        self,
207        build: B,
208        boundary: Boundary,
209        parts: F,
210    ) -> Transfer<stream::Stream<'d, B, O>, <B as body::Push<'d>>::Error>
211    where
212        B: body::Push<'d>,
213        I: input::Parts<'d>,
214        F: FnOnce(S) -> I,
215    {
216        let Self {
217            mut state,
218            storage: store,
219        } = self;
220        let transfer = match store {
221            Some(store) => flow::Flow::try_parts::<false, _>(
222                build,
223                parts(store),
224                state.logical_len(),
225                segments::Count::EMPTY,
226            ),
227            None if state.retention() == admit::Retention::Retained && state.logical_len() != 0 => {
228                flow::Push::Failed {
229                    build: flow::Flow::new(build),
230                    error: body::Error::SegmentMismatch,
231                }
232            }
233            None => flow::Push::Accepted(flow::Flow::new(build)),
234        };
235        let transfer = match boundary {
236            Boundary::End => match transfer {
237                flow::Push::Accepted(flow) => match flow.try_complete(&mut state) {
238                    body::Transfer::Accepted(flow) => flow::Push::Accepted(flow),
239                    body::Transfer::Rejected { build, error } => {
240                        flow::Push::Failed { build, error }
241                    }
242                },
243                failed => failed,
244            },
245            Boundary::More => transfer,
246        };
247        match transfer {
248            flow::Push::Accepted(flow) => Ok(stream::Stream::from_parts(state, flow)),
249            flow::Push::Failed { build: flow, error } => {
250                let stream = stream::Stream::from_parts(state, flow);
251                Err(mem::Rejected::new(stream, Transition::Body(error)))
252            }
253            flow::Push::Rejected { build: flow, error } => {
254                let stream = stream::Stream::from_parts(state, flow);
255                Err(mem::Rejected::new(stream, Transition::Build(error)))
256            }
257        }
258    }
259}
260
261const _: () = {
262    assert!(core::mem::size_of::<Error<u8>>() == 3 * core::mem::size_of::<usize>());
263    assert!(core::mem::size_of::<Result<(), Error<u8>>>() == 3 * core::mem::size_of::<usize>());
264    assert!(core::mem::size_of::<Transition<u8>>() == 3 * core::mem::size_of::<usize>());
265    assert!(
266        core::mem::size_of::<Result<(), Transition<u8>>>() == 3 * core::mem::size_of::<usize>()
267    );
268};