Skip to main content

sark_core/request/
raw.rs

1use std::ops;
2
3use o3::buffer::{bytes::scope, pool, pool::owners, storage};
4use sark_http::{
5    field::metadata::section::storage::Bytes,
6    payload::owned,
7    request,
8    request::{Id, Layout, Source},
9};
10
11use crate::{
12    body,
13    request::{BindError, Head, Parts, Retained, frame::proof},
14    route,
15};
16
17pub trait Bind: request::raw::Bind {
18    /// # Safety
19    /// `self` and all ranges must satisfy [`request::raw::Bind::try_bind`]'s native decoder,
20    /// closed policy, and exact original field-range requirements.
21    unsafe fn try_head<P: proof::Proof>(
22        self,
23        path: Option<ops::Range<usize>>,
24        path_len: Option<usize>,
25        pseudo: Option<ops::Range<usize>>,
26        host: Option<ops::Range<usize>>,
27    ) -> Result<Head<Self::Owner, P>, BindError> {
28        // SAFETY: the caller preserves the exact native head and field ranges.
29        let bound = unsafe { request::raw::Bind::try_bind(self, path, path_len, pseudo, host) }
30            .map_err(BindError::Layout)?;
31        Head::try_bound(bound)
32    }
33}
34
35impl<H: request::raw::Bind> Bind for H {}
36
37/// A parsed schema bound to the immutable request that produced its fields.
38pub struct Parsed<H, R: route::Schema> {
39    owner: H,
40    params: R::RawParams,
41    headers: R::RawHeaders,
42}
43
44impl<O: Source, F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Head<O, F>, R> {
45    /// # Safety
46    /// `layout` must be valid for the exact bytes retained by `owner`, and both field sets must be produced by `R` from those bytes.
47    /// Replacing the owner must preserve the complete head bytes and their offsets.
48    pub unsafe fn try_bind(
49        owner: O,
50        layout: Layout,
51        params: R::RawParams,
52        headers: R::RawHeaders,
53    ) -> Result<Self, BindError> {
54        // SAFETY: the caller carries the admitted layout with its exact owner.
55        let owner = unsafe { Head::try_parts(owner, layout) }?;
56        // SAFETY: the same owner retains both schema field sets' byte origin.
57        Ok(unsafe { Self::new(owner, params, headers) })
58    }
59
60    /// # Safety
61    /// Both field sets must be produced by `R` from this exact head.
62    pub const unsafe fn new(
63        owner: Head<O, F>,
64        params: R::RawParams,
65        headers: R::RawHeaders,
66    ) -> Self {
67        Self {
68            owner,
69            params,
70            headers,
71        }
72    }
73
74    pub fn borrow(&self) -> Parsed<Head<&[u8], F>, R> {
75        Parsed {
76            owner: self.owner.borrow(),
77            params: self.params,
78            headers: self.headers,
79        }
80    }
81}
82
83impl<H, R: route::Schema> Parsed<H, R> {
84    pub const fn owner(&self) -> &H {
85        &self.owner
86    }
87
88    pub fn into_owner(self) -> H {
89        self.owner
90    }
91
92    pub const fn params(&self) -> &R::RawParams {
93        &self.params
94    }
95
96    pub const fn headers(&self) -> &R::RawHeaders {
97        &self.headers
98    }
99}
100
101impl<F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Head<Bytes, F>, R> {
102    pub fn retain(self) -> Parsed<Head<storage::Shared, F>, R> {
103        Parsed {
104            owner: self.owner.retain(),
105            params: self.params,
106            headers: self.headers,
107        }
108    }
109}
110
111impl<F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Head<storage::Shared, F>, R> {
112    pub fn with_id<'d>(self, id: Id<'d>) -> Parsed<Parts<'d, F>, R> {
113        Parsed {
114            owner: Parts::from_head(id, self.owner),
115            params: self.params,
116            headers: self.headers,
117        }
118    }
119}
120
121impl<'d, F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Parts<'d, F>, R> {
122    pub fn with_body(self, body: body::Body<owned::Segments<'d>>) -> Parsed<Retained<'d, F>, R> {
123        Parsed {
124            owner: Retained {
125                parts: self.owner,
126                body,
127            },
128            params: self.params,
129            headers: self.headers,
130        }
131    }
132}
133
134impl<'d, F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Retained<'d, F>, R> {
135    pub fn into_parts(self) -> (Parsed<Parts<'d, F>, R>, body::Body<owned::Segments<'d>>) {
136        let (parts, body) = self.owner.into_parts();
137        (
138            Parsed {
139                owner: parts,
140                params: self.params,
141                headers: self.headers,
142            },
143            body,
144        )
145    }
146}
147
148impl<F: proof::Proof, R: route::Schema<Frame = F>> Parsed<Head<Bytes, F>, R> {
149    pub fn scope<T>(
150        self,
151        use_head: impl for<'id> FnOnce(
152            Parsed<
153                Head<
154                    Bytes<
155                        scope::Owner<
156                            'id,
157                            pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>,
158                        >,
159                    >,
160                    F,
161                >,
162                R,
163            >,
164        ) -> T,
165    ) -> T {
166        let Self {
167            owner,
168            params,
169            headers,
170        } = self;
171        owner.scope(|owner| {
172            use_head(Parsed {
173                owner,
174                params,
175                headers,
176            })
177        })
178    }
179}
180
181impl<F: proof::Proof, R: route::Schema<Frame = F>>
182    Parsed<
183        Head<
184            Bytes<
185                scope::Owner<
186                    '_,
187                    pool::Span<owners::Plain<pool::Layout>, pool::Owned, pool::Frozen>,
188                >,
189            >,
190            F,
191        >,
192        R,
193    >
194{
195    pub fn into_inner(self) -> Parsed<Head<Bytes, F>, R> {
196        Parsed {
197            owner: self.owner.into_inner(),
198            params: self.params,
199            headers: self.headers,
200        }
201    }
202}