Skip to main content

sark_core/http/response/
body.rs

1use o3::buffer::{Owned, Shared};
2
3use super::TextBody;
4use crate::http::LocalFrameBytesRef;
5
6#[derive(Clone)]
7pub enum BodyInner<'req> {
8    Owned(Owned),
9    Shared(Shared),
10    Local(LocalFrameBytesRef<'req>),
11    StaticSlice(&'static [u8]),
12}
13
14pub type Body = BodyInner<'static>;
15
16impl<'req> std::fmt::Debug for BodyInner<'req> {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        match self {
19            Self::Owned(buf) => f
20                .debug_struct("Body::Owned")
21                .field("len", &buf.len())
22                .finish(),
23            Self::Shared(buf) => f
24                .debug_struct("Body::Shared")
25                .field("len", &buf.len())
26                .finish(),
27            Self::Local(buf) => f
28                .debug_struct("Body::Local")
29                .field("len", &buf.len())
30                .finish(),
31            Self::StaticSlice(buf) => f
32                .debug_struct("Body::StaticSlice")
33                .field("len", &buf.len())
34                .finish(),
35        }
36    }
37}
38
39impl<'req> BodyInner<'req> {
40    pub(crate) fn empty() -> Self {
41        Self::Owned(Owned::new())
42    }
43
44    pub(crate) fn len(&self) -> usize {
45        match self {
46            Self::Owned(buf) => buf.len(),
47            Self::Shared(buf) => buf.len(),
48            Self::Local(buf) => buf.len(),
49            Self::StaticSlice(buf) => buf.len(),
50        }
51    }
52
53    pub(crate) fn as_bytes(&self) -> &[u8] {
54        match self {
55            Self::Owned(buf) => buf.as_ref(),
56            Self::Shared(buf) => buf.as_ref(),
57            Self::Local(buf) => buf.as_bytes(),
58            Self::StaticSlice(buf) => buf,
59        }
60    }
61
62    pub(crate) fn is_shared(&self) -> bool {
63        matches!(
64            self,
65            Self::Shared(_) | Self::Local(_) | Self::StaticSlice(_)
66        )
67    }
68
69    pub(crate) fn into_bytes(self) -> Shared {
70        match self {
71            Self::Owned(buf) => buf.freeze(),
72            Self::Shared(buf) => buf,
73            Self::Local(buf) => buf.into_bytes(),
74            Self::StaticSlice(buf) => Shared::from_static(buf),
75        }
76    }
77
78    pub(crate) fn into_owned(self) -> Owned {
79        match self {
80            Self::Owned(buf) => buf,
81            Self::Shared(buf) => Owned::from(buf.as_ref()),
82            Self::Local(buf) => Owned::from(buf.as_bytes()),
83            Self::StaticSlice(buf) => Owned::from(buf),
84        }
85    }
86
87    pub(crate) fn as_owned_mut(&mut self) -> &mut Owned {
88        if matches!(
89            self,
90            Self::Shared(_) | Self::Local(_) | Self::StaticSlice(_)
91        ) {
92            let old = std::mem::replace(self, Self::empty());
93            *self = Self::Owned(old.into_owned());
94        }
95        match self {
96            Self::Owned(buf) => buf,
97            _ => unreachable!("response body must be owned after conversion"),
98        }
99    }
100}
101
102pub trait IntoBody<'req>: sealed::SealedBody {
103    fn into_response_body(self) -> BodyInner<'req>;
104}
105
106impl<'req> IntoBody<'req> for BodyInner<'req> {
107    fn into_response_body(self) -> Self {
108        self
109    }
110}
111
112impl<'req> IntoBody<'req> for Owned {
113    fn into_response_body(self) -> BodyInner<'req> {
114        BodyInner::Owned(self)
115    }
116}
117
118impl<'req> IntoBody<'req> for Shared {
119    fn into_response_body(self) -> BodyInner<'req> {
120        BodyInner::Shared(self)
121    }
122}
123
124impl<'req> IntoBody<'req> for LocalFrameBytesRef<'req> {
125    fn into_response_body(self) -> BodyInner<'req> {
126        BodyInner::Local(self)
127    }
128}
129
130impl<'req> IntoBody<'req> for TextBody {
131    fn into_response_body(self) -> BodyInner<'req> {
132        BodyInner::Shared(self.into_bytes())
133    }
134}
135
136impl<'req> IntoBody<'req> for Vec<u8> {
137    fn into_response_body(self) -> BodyInner<'req> {
138        BodyInner::Owned(Owned::from(self.as_slice()))
139    }
140}
141
142impl<'req> IntoBody<'req> for String {
143    fn into_response_body(self) -> BodyInner<'req> {
144        BodyInner::Owned(Owned::from(self.as_bytes()))
145    }
146}
147
148impl<'req> IntoBody<'req> for &[u8] {
149    fn into_response_body(self) -> BodyInner<'req> {
150        BodyInner::Owned(Owned::from(self))
151    }
152}
153
154impl<'req> IntoBody<'req> for &str {
155    fn into_response_body(self) -> BodyInner<'req> {
156        BodyInner::Owned(Owned::from(self.as_bytes()))
157    }
158}
159
160mod sealed {
161    use super::super::{LocalFrameBytesRef, TextBody};
162    use super::BodyInner;
163
164    pub trait SealedBody {}
165
166    impl<'req> SealedBody for BodyInner<'req> {}
167    impl SealedBody for TextBody {}
168    impl SealedBody for o3::buffer::Owned {}
169    impl SealedBody for o3::buffer::Shared {}
170    impl<'req> SealedBody for LocalFrameBytesRef<'req> {}
171    impl SealedBody for Vec<u8> {}
172    impl SealedBody for String {}
173    impl SealedBody for &[u8] {}
174    impl SealedBody for &str {}
175}