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#[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#[derive(Debug)]
28pub enum Error<E> {
29 Body(body::Error),
30 Retain(E),
31}
32
33#[derive(Debug)]
35pub enum Transition<E> {
36 Body(body::Error),
37 Build(E),
38}
39
40#[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#[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 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 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};