Skip to main content

sark_http/owner/handoff/
input.rs

1use std::{borrow::Borrow, marker::PhantomData};
2
3use o3::buffer::bytes::scope;
4
5use crate::{
6    owner::handoff::{Origin, Project, Slot, origin, stage},
7    payload::owned,
8    request::body::{self, Source as _},
9};
10
11/// A projection from a borrowed source; it cannot defer ownership transfer.
12pub struct Borrowed<'a, S>(&'a mut S);
13
14impl<'a, S> Borrowed<'a, S> {
15    pub const fn new(source: &'a mut S) -> Self {
16        Self(source)
17    }
18}
19
20impl<'a, 'd, S: body::Source<'d>> Project<'d> for Borrowed<'a, S> {
21    type Proof = ();
22    type Owner = ();
23
24    fn contiguous<V, T>(
25        self,
26        value: V,
27        project: impl for<'req> FnOnce(
28            V,
29            body::View<'req, 'd>,
30            Slot<'req, 'd, (), Bound<'req, 'd, ()>>,
31        ) -> T,
32    ) -> Result<(T, ()), (Self, V, body::Error)> {
33        match self.0.try_project(value, |value, view| {
34            project(value, view, Bound::slot(view.into(), ()))
35        }) {
36            Ok(output) => Ok((output, ())),
37            Err((value, error)) => Err((self, value, error)),
38        }
39    }
40
41    fn segmented<V, T>(
42        self,
43        value: V,
44        project: impl for<'req> FnOnce(
45            V,
46            body::Ref<'req, 'd>,
47            Slot<'req, 'd, (), Bound<'req, 'd, ()>>,
48        ) -> T,
49    ) -> (T, ()) {
50        let view = self.0.body().into();
51        (project(value, view, Bound::slot(view, ())), ())
52    }
53
54    fn discarded<V, T>(
55        self,
56        value: V,
57        project: impl for<'req> FnOnce(V, Slot<'req, 'd, (), Bound<'req, 'd, ()>>) -> T,
58    ) -> (T, ()) {
59        (
60            project(value, Bound::slot(body::Ref::from_slice(&[]), ())),
61            (),
62        )
63    }
64}
65
66/// The original source, before its one selected projection.
67pub struct Input<'owner, 'd>(scope::Owner<'owner, ()>, owned::Segments<'d>);
68
69/// The exact final source after normalization and response selection.
70pub struct Frozen<'owner, 'd>(Input<'owner, 'd>);
71
72/// A selected source whose short borrow can end without losing owner identity.
73#[derive(Clone, Copy)]
74pub struct Bound<'req, 'd, P> {
75    body: body::Retained<'req, 'd>,
76    proof: P,
77}
78
79/// An ownership selection with no borrow of the source storage.
80#[derive(Clone, Copy)]
81pub struct Selected<'owner>(PhantomData<*mut &'owner ()>);
82
83impl<'d> Input<'_, 'd> {
84    pub fn with<T>(
85        source: owned::Segments<'d>,
86        run: impl for<'owner> FnOnce(Input<'owner, 'd>) -> T,
87    ) -> T {
88        scope::Owner::with((), |brand| run(Input(brand, source)))
89    }
90}
91
92impl<'req, 'd, P: stage::Proof> Bound<'req, 'd, P> {
93    fn slot(view: body::Ref<'req, 'd>, proof: P) -> Slot<'req, 'd, (), Self> {
94        let source = match view.try_retained() {
95            Ok(body) => origin::Source::Retained(Self { body, proof }),
96            Err(body) if body.is_empty() => origin::Source::Empty,
97            Err(_) => origin::Source::Borrowed(PhantomData),
98        };
99        Slot {
100            origin: Origin { source },
101            head: (),
102        }
103    }
104}
105
106impl<'owner, 'd> Project<'d> for Input<'owner, 'd> {
107    type Proof = Selected<'owner>;
108    type Owner = Frozen<'owner, 'd>;
109
110    fn contiguous<V, T>(
111        mut self,
112        value: V,
113        project: impl for<'req> FnOnce(
114            V,
115            body::View<'req, 'd>,
116            Slot<'req, 'd, (), Bound<'req, 'd, Selected<'owner>>>,
117        ) -> T,
118    ) -> Result<(T, Self::Owner), (Self, V, body::Error)> {
119        let output = self.1.try_project(value, |value, view| {
120            project(value, view, Bound::slot(view.into(), Selected(PhantomData)))
121        });
122        match output {
123            Ok(output) => Ok((output, Frozen(self))),
124            Err((value, error)) => Err((self, value, error)),
125        }
126    }
127
128    fn segmented<V, T>(
129        self,
130        value: V,
131        project: impl for<'req> FnOnce(
132            V,
133            body::Ref<'req, 'd>,
134            Slot<'req, 'd, (), Bound<'req, 'd, Selected<'owner>>>,
135        ) -> T,
136    ) -> (T, Self::Owner) {
137        let view = body::Ref::from(&self.1);
138        let output = project(value, view, Bound::slot(view, Selected(PhantomData)));
139        (output, Frozen(self))
140    }
141
142    fn discarded<V, T>(
143        self,
144        value: V,
145        project: impl for<'req> FnOnce(V, Slot<'req, 'd, (), Bound<'req, 'd, Selected<'owner>>>) -> T,
146    ) -> (T, Self::Owner) {
147        let output = project(
148            value,
149            Bound::slot(body::Ref::from_slice(&[]), Selected(PhantomData)),
150        );
151        (output, Frozen(self))
152    }
153}
154
155impl<'req, 'd, P> Borrow<body::Retained<'req, 'd>> for Bound<'req, 'd, P> {
156    fn borrow(&self) -> &body::Retained<'req, 'd> {
157        &self.body
158    }
159}
160
161impl<'req, 'd: 'req, P: stage::Proof> stage::Body<'req, 'd> for Bound<'req, 'd, P> {
162    type Deferred = P::Deferred;
163
164    fn defer(self) -> Self::Deferred {
165        self.proof.defer(self.body)
166    }
167}
168
169impl stage::Proof for Selected<'_> {
170    type Deferred = Self;
171
172    fn defer(self, _: body::Retained<'_, '_>) -> Self {
173        self
174    }
175}
176
177impl<'owner, 'd> stage::Deferred<'d> for Selected<'owner> {
178    type Owner = Frozen<'owner, 'd>;
179
180    fn resolve(self, owner: Self::Owner) -> owned::Segments<'d> {
181        let Input(brand, body) = owner.0;
182        brand.into_inner();
183        body
184    }
185}
186
187const _: () = {
188    assert!(size_of::<Input<'static, 'static>>() == size_of::<owned::Segments<'static>>());
189    assert!(size_of::<Frozen<'static, 'static>>() == size_of::<owned::Segments<'static>>());
190    assert!(
191        size_of::<Bound<'static, 'static, Selected<'static>>>()
192            == size_of::<body::Retained<'static, 'static>>()
193    );
194    assert!(size_of::<Selected<'static>>() == 0);
195};