Skip to main content

sark_core/http/response/
static_response.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
10/// A response whose body is guaranteed to live for the entire process.
11///
12/// Keeping the static slice directly avoids paying for the largest variant of
13/// `Body` on generated static-response routes.
14#[derive(Clone, Debug)]
15pub struct StaticResponseInner<
16    'req,
17    const N: usize = DEFAULT_HEADER_CAPACITY,
18    S = StaticHeaderBytes,
19> {
20    pub(super) status: StatusCode,
21    pub(super) head: HeadInner<'req, N, S>,
22    pub(super) body: &'static [u8],
23}
24
25impl<'req, const N: usize> StaticResponseInner<'req, N> {
26    pub fn direct(
27        status: StatusCode,
28        static_headers: &'static [u8],
29        headers: Headers<'req, N>,
30        body: &'static [u8],
31    ) -> Self {
32        Self {
33            status,
34            head: HeadInner::new(static_headers, headers),
35            body,
36        }
37    }
38}
39
40impl<'req, const N: usize> StaticResponseInner<'req, N, StaticHeaderFields> {
41    #[doc(hidden)]
42    pub fn structured(
43        status: StatusCode,
44        static_headers: &'static HeaderTemplate,
45        headers: Headers<'req, N>,
46        body: &'static [u8],
47    ) -> Self {
48        Self {
49            status,
50            head: HeadInner::structured(static_headers, headers),
51            body,
52        }
53    }
54}
55
56impl<'req, const N: usize, S> StaticResponseInner<'req, N, S>
57where
58    S: StaticHeaders,
59{
60    pub fn status(&self) -> StatusCode {
61        self.status
62    }
63
64    pub fn body_ref(&self) -> &'static [u8] {
65        self.body
66    }
67
68    pub fn wire_headers(&self) -> Shared {
69        self.head.wire_headers()
70    }
71
72    fn head_write(&self) -> HeadWrite<'_, HeadInner<'req, N, S>, ContentLength> {
73        HeadWrite {
74            status: self.status,
75            headers: &self.head,
76            framing: ContentLength(self.body.len()),
77        }
78    }
79
80    pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
81        let head = self.head_write();
82        let total = head.wire_len().checked_add(self.body.len())?;
83        let mut out = ProvenWireWriter::new(out, total)?;
84        head.emit(&mut out, date);
85        out.put(self.body);
86        Some(out.finish(total))
87    }
88
89    pub fn write_head_only(
90        &self,
91        out: &mut [u8],
92        date: &[u8; 29],
93    ) -> Option<(usize, &'static [u8])> {
94        let head = self.head_write();
95        let head_len = head.wire_len();
96        let mut out = ProvenWireWriter::new(out, head_len)?;
97        head.emit(&mut out, date);
98        Some((out.finish(head_len), self.body))
99    }
100
101    pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
102        let (off, body) = self.write_head_only(out, date)?;
103        Some((off, Shared::from_static(body)))
104    }
105
106    pub fn preserialize_static(&self) -> (Vec<u8>, usize, &'static [u8]) {
107        let head = self.head_write();
108        let head_len = head.wire_len();
109        let mut out = vec![0u8; head_len];
110        let mut writer = ProvenWireWriter::exact(&mut out);
111        let date_offset = head.emit(&mut writer, PLACEHOLDER_DATE);
112        writer.finish(head_len);
113        (out, date_offset, self.body)
114    }
115}