1use std::iter::FusedIterator;
2
3use o3::buffer::{
4 bytes::scope,
5 hold::ranges,
6 segments, storage,
7 write::{Sink as _, consume},
8};
9
10use crate::{
11 owner::{handoff, handoff::stage},
12 payload::{
13 owned::{self, Segments},
14 response,
15 response::Body as _,
16 },
17};
18
19mod error;
20pub mod iter;
21mod retained;
22mod view;
23
24pub use error::Error;
25#[doc(hidden)]
26pub use retained::Retained;
27pub use view::View;
28
29pub trait Source<'d> {
32 type Body<'a>: Into<Ref<'a, 'd>>
33 where
34 Self: 'a,
35 'd: 'a;
36
37 fn try_project<V, T>(
38 &mut self,
39 value: V,
40 project: impl for<'a> FnOnce(V, View<'a, 'd>) -> T,
41 ) -> Result<T, (V, Error)>;
42
43 fn body<'a>(&'a self) -> Self::Body<'a>
44 where
45 'd: 'a;
46}
47
48#[derive(Clone, Copy, Debug)]
49enum RefStorage<'req, 'd> {
50 Discarded,
51 Empty(&'req [u8]),
52 Slice(&'req [u8]),
54 Retained(Retained<'req, 'd>),
55 Ranges(&'req ranges::Set<'req, 'req, [u8]>),
56}
57
58#[derive(Clone, Copy, Debug)]
60pub struct Ref<'req, 'd> {
61 storage: RefStorage<'req, 'd>,
62 len: usize,
63}
64
65impl<'req, 'd> Ref<'req, 'd> {
66 pub const fn from_slice(bytes: &'req [u8]) -> Self {
68 let storage = if bytes.is_empty() {
69 RefStorage::Empty(bytes)
70 } else {
71 RefStorage::Slice(bytes)
72 };
73 Self {
74 storage,
75 len: bytes.len(),
76 }
77 }
78
79 #[doc(hidden)]
80 pub const fn discarded(len: usize) -> Self {
81 Self {
82 storage: RefStorage::Discarded,
83 len,
84 }
85 }
86
87 #[doc(hidden)]
88 pub const fn from_ranges(ranges: &'req ranges::Set<'req, 'req, [u8]>) -> Self {
89 Self {
90 storage: RefStorage::Ranges(ranges),
91 len: ranges.len(),
92 }
93 }
94
95 pub const fn len(&self) -> usize {
96 self.len
97 }
98
99 pub const fn is_empty(&self) -> bool {
100 self.len == 0
101 }
102
103 pub fn count(&self) -> segments::Count {
104 match self.storage {
105 RefStorage::Discarded | RefStorage::Empty(_) => segments::Count::EMPTY,
106 RefStorage::Slice(_) => segments::Count::ONE,
107 RefStorage::Retained(body) => body.count(),
108 RefStorage::Ranges(ranges) => ranges.count(),
109 }
110 }
111
112 pub fn segment(&self, index: usize) -> Option<&'req [u8]> {
113 match self.storage {
114 RefStorage::Discarded | RefStorage::Empty(_) => None,
115 RefStorage::Slice(bytes) => (index == 0).then_some(bytes),
116 RefStorage::Retained(body) => body.segment(index),
117 RefStorage::Ranges(ranges) => ranges.get(index).map(|view| view.as_slice()),
118 }
119 }
120
121 pub fn segments(self) -> iter::Slices<'req, 'd> {
122 iter::Slices::new(self)
123 }
124
125 pub fn as_slice(&self) -> Option<&'req [u8]> {
126 match self.storage {
127 RefStorage::Discarded => None,
128 RefStorage::Empty(bytes) => Some(bytes),
129 RefStorage::Slice(bytes) => Some(bytes),
130 RefStorage::Retained(body) => body.as_slice(),
131 RefStorage::Ranges(ranges) => ranges.contiguous(),
132 }
133 }
134
135 pub fn try_copy(self) -> Result<storage::Shared, owned::Error> {
137 if let RefStorage::Discarded = self.storage {
138 return Err(owned::Error::Discarded);
139 }
140 storage::Exact::try_build(self.len(), |out| {
141 for part in self.segments() {
142 out.write_slice(part)?;
143 }
144 Ok::<(), consume::Error>(())
145 })
146 .map(storage::Exact::into_shared)
147 .map_err(owned::Error::Build)
148 }
149
150 pub(crate) const fn try_retained(self) -> Result<Retained<'req, 'd>, Self> {
151 match self.storage {
152 RefStorage::Retained(body) => Ok(body),
153 _ => Err(self),
154 }
155 }
156}
157
158impl<'src, 'd> response::Body<'d> for Ref<'src, 'd> {
159 const INLINE: bool = true;
160
161 fn len(&self) -> usize {
162 self.len
163 }
164
165 fn as_slice(&self) -> Option<&[u8]> {
166 Self::as_slice(self)
167 }
168
169 fn segments(&self) -> impl ExactSizeIterator<Item = &[u8]> + FusedIterator {
170 iter::Slices::new(*self)
171 }
172
173 fn try_resolve<'req, H: scope::Source, O: stage::Body<'req, 'd>>(
174 self,
175 slot: &handoff::Slot<'req, 'd, H, O>,
176 ) -> Result<handoff::Plan<'req, 'd, H::Selection, O>, owned::Error> {
177 let origin = slot.origin();
178 if !self.is_empty() {
179 if let RefStorage::Retained(view) = self.storage {
180 return handoff::Plan::try_retain(origin, view);
181 }
182 return handoff::Plan::try_view(origin, self);
183 }
184 Ok(handoff::Plan::new(origin.clear()))
185 }
186}
187
188impl<'d> Source<'d> for &[u8] {
189 type Body<'a>
190 = Ref<'a, 'd>
191 where
192 Self: 'a,
193 'd: 'a;
194
195 fn try_project<V, T>(
196 &mut self,
197 value: V,
198 project: impl for<'a> FnOnce(V, View<'a, 'd>) -> T,
199 ) -> Result<T, (V, Error)> {
200 Ok(project(value, View::Slice(self)))
201 }
202
203 fn body<'a>(&'a self) -> Self::Body<'a>
204 where
205 'd: 'a,
206 {
207 Ref::from_slice(self)
208 }
209}
210
211impl<'req, 'd> Source<'d> for Ref<'req, 'd> {
212 type Body<'a>
213 = Ref<'a, 'd>
214 where
215 Self: 'a,
216 'd: 'a;
217
218 fn try_project<V, T>(
219 &mut self,
220 value: V,
221 project: impl for<'a> FnOnce(V, View<'a, 'd>) -> T,
222 ) -> Result<T, (V, Error)> {
223 let view = match self.storage {
224 RefStorage::Retained(owner) => owner.contiguous(),
225 _ => self.as_slice().map(View::Slice),
226 };
227 match view {
228 Some(view) => Ok(project(value, view)),
229 None => Err((
230 value,
231 Error::Borrowed {
232 len: self.len(),
233 count: self.count(),
234 },
235 )),
236 }
237 }
238
239 fn body<'a>(&'a self) -> Self::Body<'a>
240 where
241 'd: 'a,
242 {
243 *self
244 }
245}
246
247const _: () = {
248 assert!(core::mem::size_of::<Ref<'static, 'static>>() == 4 * core::mem::size_of::<usize>());
249};
250
251impl<'req, 'd> From<&'req Segments<'d>> for Ref<'req, 'd> {
252 fn from(body: &'req Segments<'d>) -> Self {
253 Self {
254 storage: RefStorage::Retained(Retained::Segments(body)),
255 len: body.len(),
256 }
257 }
258}