Skip to main content

sark_core/http/response/direct/
plan.rs

1use http::StatusCode;
2use o3::buffer::{Borrowed, Bytes, Owned, Retained, Shared};
3
4use super::super::{HotBodyInner, HotHeadInner, IntoBody, MonoResponseInner};
5use super::head::HeadInner;
6use super::headers::{HeaderAssert, HeaderNameToken, HeaderStaticValueToken, HeadersInner};
7use super::value::{InlineHeaderValue, TextSpec};
8
9#[derive(Clone, Debug)]
10pub struct ResponsePlanInner<'req> {
11    pub(in crate::http::response) status: StatusCode,
12    pub(in crate::http::response) head: HeadInner<'req>,
13}
14
15pub type ResponsePlan = ResponsePlanInner<'static>;
16
17impl<'req> ResponsePlanInner<'req> {
18    pub fn with_capacity(status: StatusCode) -> Self {
19        Self {
20            status,
21            head: HeadInner::new(b"", HeadersInner::new()),
22        }
23    }
24
25    pub fn from_static(status: StatusCode, static_headers: &'static [u8]) -> Self {
26        Self {
27            status,
28            head: HeadInner::new(static_headers, HeadersInner::new()),
29        }
30    }
31
32    pub fn new(status: StatusCode) -> Self {
33        Self::with_capacity(status)
34    }
35
36    pub fn ok() -> Self {
37        Self::new(StatusCode::OK)
38    }
39
40    pub fn not_found() -> Self {
41        Self::new(StatusCode::NOT_FOUND)
42    }
43
44    pub fn status(&self) -> StatusCode {
45        self.status
46    }
47
48    pub fn wire_headers(&self) -> Shared {
49        let mut out = Owned::with_capacity(self.head.wire_len());
50        self.head.write_into_owned(&mut out);
51        out.freeze()
52    }
53
54    pub fn push_static(&mut self, name: &'static str, value: &'static str) -> &mut Self {
55        let name = HeaderNameToken::new(name);
56        let value = HeaderStaticValueToken::new(value);
57        self.head.headers_mut().push_static(name, value);
58        self
59    }
60
61    pub fn push(&mut self, name: &'static str, value: &str) -> &mut Self {
62        self.push_str_value(HeaderNameToken::new(name), value)
63    }
64
65    pub fn push_token_static(
66        &mut self,
67        name: HeaderNameToken,
68        value: HeaderStaticValueToken,
69    ) -> &mut Self {
70        self.head.headers_mut().push_static(name, value);
71        self
72    }
73
74    pub fn push_token(&mut self, name: HeaderNameToken, value: &str) -> &mut Self {
75        self.push_str_value(name, value)
76    }
77
78    fn push_str_value(&mut self, name: HeaderNameToken, value: &str) -> &mut Self {
79        HeaderAssert::value(value);
80        if value.len() <= 31 {
81            self.head
82                .headers_mut()
83                .push_inline(name, InlineHeaderValue::new(value.as_bytes()));
84        } else {
85            self.head
86                .headers_mut()
87                .push_shared(name, Shared::copy_from_slice(value.as_bytes()));
88        }
89        self
90    }
91
92    pub fn push_borrowed_token(
93        &mut self,
94        name: HeaderNameToken,
95        value: Bytes<Borrowed<'req>>,
96    ) -> &mut Self {
97        HeaderAssert::value_bytes(value.as_slice());
98        self.head.headers_mut().push_borrowed(name, value);
99        self
100    }
101
102    pub fn push_retained_token(
103        &mut self,
104        name: HeaderNameToken,
105        value: Bytes<Retained>,
106    ) -> &mut Self {
107        HeaderAssert::value_bytes(value.as_slice());
108        self.head.headers_mut().push_retained(name, value);
109        self
110    }
111
112    pub fn respond_mono<B>(self, body: B) -> MonoResponseInner<'req>
113    where
114        B: IntoBody<'req>,
115    {
116        let status = self.status;
117        MonoResponseInner {
118            status,
119            headers: None,
120            head: HotHeadInner::Direct(self.head),
121            body: HotBodyInner::from(body.into_response_body()),
122        }
123    }
124
125    pub fn respond_text<T>(self, body: T) -> MonoResponseInner<'req>
126    where
127        T: TextSpec<'req>,
128    {
129        let status = self.status;
130        MonoResponseInner {
131            status,
132            headers: None,
133            head: HotHeadInner::Direct(self.head),
134            body: HotBodyInner::Text(body.into_hot_text()),
135        }
136    }
137}