Skip to main content

sark_core/http/response/
static_response.rs

1use http::StatusCode;
2use o3::buffer::{Owned, Shared};
3
4use super::wire_emit::{ContentLength, HeadWrite, PLACEHOLDER_DATE, WireWriter};
5use super::{DEFAULT_HEADER_CAPACITY, HeadInner, Headers};
6
7/// A response whose body is guaranteed to live for the entire process.
8///
9/// Keeping the static slice directly avoids paying for the largest variant of
10/// `HotBodyInner` on generated static-response routes.
11#[derive(Clone, Debug)]
12pub struct StaticResponseInner<'req, const N: usize = DEFAULT_HEADER_CAPACITY> {
13    status: StatusCode,
14    head: HeadInner<'req, N>,
15    body: &'static [u8],
16}
17
18impl<'req, const N: usize> StaticResponseInner<'req, N> {
19    pub fn direct(
20        status: StatusCode,
21        static_headers: &'static [u8],
22        headers: Headers<'req, N>,
23        body: &'static [u8],
24    ) -> Self {
25        Self {
26            status,
27            head: HeadInner::new(static_headers, headers),
28            body,
29        }
30    }
31
32    pub fn status(&self) -> StatusCode {
33        self.status
34    }
35
36    pub fn body_ref(&self) -> &'static [u8] {
37        self.body
38    }
39
40    pub fn wire_headers(&self) -> Shared {
41        let mut out = Owned::with_capacity(self.head.wire_len());
42        self.head.write_into_owned(&mut out);
43        out.freeze()
44    }
45
46    fn head_write(&self) -> HeadWrite<'_, HeadInner<'req, N>, ContentLength> {
47        HeadWrite {
48            status_str: self.status.as_str().as_bytes(),
49            reason: self
50                .status
51                .canonical_reason()
52                .map(str::as_bytes)
53                .unwrap_or(b""),
54            headers: &self.head,
55            framing: ContentLength(self.body.len()),
56        }
57    }
58
59    pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
60        let head = self.head_write();
61        let total = head.wire_len().checked_add(self.body.len())?;
62        if out.len() < total {
63            return None;
64        }
65        let written = head.write(out, date);
66        let mut out = WireWriter::at(out, written.len);
67        out.put(self.body);
68        Some(out.len())
69    }
70
71    pub fn write_head_only(
72        &self,
73        out: &mut [u8],
74        date: &[u8; 29],
75    ) -> Option<(usize, &'static [u8])> {
76        let head = self.head_write();
77        if out.len() < head.wire_len() {
78            return None;
79        }
80        let written = head.write(out, date);
81        Some((written.len, self.body))
82    }
83
84    pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
85        let (off, body) = self.write_head_only(out, date)?;
86        Some((off, Shared::from_static(body)))
87    }
88
89    pub fn preserialize_static(&self) -> (Vec<u8>, usize, &'static [u8]) {
90        let head = self.head_write();
91        let mut out = vec![0u8; head.wire_len()];
92        let written = head.write(&mut out, PLACEHOLDER_DATE);
93        (out, written.date_offset, self.body)
94    }
95}