Skip to main content

sark_http/payload/owned/
mod.rs

1use std::{num::NonZero, ops::ControlFlow};
2
3use o3::{
4    buffer::{resident, storage},
5    mem,
6};
7
8pub mod flatten;
9pub mod iter;
10
11mod error;
12mod segment;
13mod segments;
14
15pub use error::Error;
16use flatten::State;
17pub use segment::Segment;
18pub use segments::Segments;
19
20/// Retained input or its single admitted, cooperatively copied output.
21#[must_use = "step or release the retained body"]
22pub struct Flatten<'d>(State<'d>);
23
24impl<'d> Flatten<'d> {
25    pub const fn new(source: Segments<'d>) -> Self {
26        Self(State::Input(source))
27    }
28
29    pub fn try_push(
30        self,
31        segment: Segment<'d>,
32    ) -> Result<Self, mem::Rejected<(Self, Segment<'d>), flatten::Error>> {
33        match self.0 {
34            State::Input(source) => match source.try_push(segment) {
35                Ok(source) => Ok(Self::new(source)),
36                Err(rejected) => {
37                    let ((source, segment), error) = rejected.into_parts();
38                    Err(mem::Rejected::new(
39                        (Self::new(source), segment),
40                        flatten::Error::Assembly(error),
41                    ))
42                }
43            },
44            state @ State::Copying(_) => Err(mem::Rejected::new(
45                (Self(state), segment),
46                flatten::Error::Finished,
47            )),
48        }
49    }
50
51    /// Empty and single-owner bodies complete without allocating or copying.
52    /// Multi-owner bodies reserve once, then copy at most `budget` bytes per call.
53    pub fn try_step(
54        self,
55        budget: NonZero<usize>,
56    ) -> Result<ControlFlow<resident::Shared<'d>, Self>, mem::Rejected<Self, storage::AllocError>>
57    {
58        use o3::buffer::segments;
59
60        let copy = match self.0 {
61            State::Input(source) => match source.storage {
62                segments::Shape::Empty => return Ok(ControlFlow::Break(resident::Shared::new())),
63                segments::Shape::One(owner) => return Ok(ControlFlow::Break(owner.into_inner())),
64                segments::Shape::Many(source) => match segments::Flatten::try_new(source) {
65                    Ok(copy) => copy,
66                    Err(rejected) => {
67                        let (source, error) = rejected.into_parts();
68                        return Err(mem::Rejected::new(
69                            Self::new(Segments::from(segments::Shape::Many(source))),
70                            error,
71                        ));
72                    }
73                },
74            },
75            State::Copying(copy) => copy,
76        };
77        Ok(match copy.step(budget) {
78            ControlFlow::Break(output) => ControlFlow::Break(resident::Shared::from(output)),
79            ControlFlow::Continue(copy) => ControlFlow::Continue(Self(State::Copying(copy))),
80        })
81    }
82}