Skip to main content

sark_core/http/response/
encoded.rs

1use http::StatusCode;
2use o3::buffer::Shared;
3
4use super::wire_emit::{ContentLength, HeadWrite, PLACEHOLDER_DATE, ProvenWireWriter};
5use super::{
6    DEFAULT_HEADER_CAPACITY, HeadInner, HeaderTemplate, Headers, StaticHeaderBytes,
7    StaticHeaderFields, StaticHeaders,
8};
9
10pub trait EncodedBody: Sized {
11    type Error;
12
13    fn encoded_len(&self) -> usize;
14
15    fn encode_into(&self, out: &mut [u8]) -> Result<(), Self::Error>;
16
17    fn into_shared(self, encoded_len: usize) -> Result<Shared, Self::Error> {
18        let mut out = vec![0; encoded_len];
19        self.encode_into(&mut out)?;
20        Ok(Shared::from(out))
21    }
22}
23
24pub struct EncodedResponse<'req, B, const N: usize = DEFAULT_HEADER_CAPACITY, S = StaticHeaderBytes>
25{
26    pub(super) status: StatusCode,
27    pub(super) head: HeadInner<'req, N, S>,
28    pub(super) body: B,
29    pub(super) body_len: usize,
30}
31
32impl<'req, B, const N: usize> EncodedResponse<'req, B, N>
33where
34    B: EncodedBody,
35{
36    pub fn direct(
37        status: StatusCode,
38        static_headers: &'static [u8],
39        headers: Headers<'req, N>,
40        body: B,
41    ) -> Self {
42        let body_len = body.encoded_len();
43        Self {
44            status,
45            head: HeadInner::new(static_headers, headers),
46            body,
47            body_len,
48        }
49    }
50}
51
52impl<'req, B, const N: usize> EncodedResponse<'req, B, N, StaticHeaderFields>
53where
54    B: EncodedBody,
55{
56    #[doc(hidden)]
57    pub fn structured(
58        status: StatusCode,
59        static_headers: &'static HeaderTemplate,
60        headers: Headers<'req, N>,
61        body: B,
62    ) -> Self {
63        let body_len = body.encoded_len();
64        Self {
65            status,
66            head: HeadInner::structured(static_headers, headers),
67            body,
68            body_len,
69        }
70    }
71}
72
73impl<'req, B, const N: usize, S> EncodedResponse<'req, B, N, S>
74where
75    B: EncodedBody,
76    S: StaticHeaders,
77{
78    pub fn status(&self) -> StatusCode {
79        self.status
80    }
81
82    pub fn wire_headers(&self) -> Shared {
83        self.head.wire_headers()
84    }
85
86    pub(crate) fn encoded_body(&self) -> Option<Shared> {
87        let mut body = vec![0; self.body_len];
88        self.body.encode_into(&mut body).ok()?;
89        Some(Shared::from(body))
90    }
91
92    fn head_write(&self) -> HeadWrite<'_, HeadInner<'req, N, S>, ContentLength> {
93        HeadWrite {
94            status: self.status,
95            headers: &self.head,
96            framing: ContentLength(self.body_len),
97        }
98    }
99
100    pub fn preserialize(&self) -> Option<(Vec<u8>, usize)> {
101        let head = self.head_write();
102        let head_len = head.wire_len();
103        let body_len = self.body_len;
104        let total = head_len.checked_add(body_len)?;
105        let mut out = vec![0u8; total];
106        let mut writer = ProvenWireWriter::exact(&mut out);
107        let date_offset = head.emit(&mut writer, PLACEHOLDER_DATE);
108        self.body.encode_into(writer.take_exact(body_len)).ok()?;
109        writer.finish(total);
110        Some((out, date_offset))
111    }
112
113    pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
114        let head = self.head_write();
115        let head_len = head.wire_len();
116        let body_len = self.body_len;
117        let total = head_len.checked_add(body_len)?;
118        let mut out = ProvenWireWriter::new(out, total)?;
119        head.emit(&mut out, date);
120        self.body.encode_into(out.take_exact(body_len)).ok()?;
121        Some(out.finish(total))
122    }
123
124    pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
125        let head = self.head_write();
126        let head_len = head.wire_len();
127        let mut out = ProvenWireWriter::new(out, head_len)?;
128        head.emit(&mut out, date);
129        let written = out.finish(head_len);
130        let body = self.body.into_shared(self.body_len).ok()?;
131        Some((written, body))
132    }
133}