1use std::{mem::ManuallyDrop, sync::Arc};
2
3use bytes::{buf::UninitSlice, Buf, BufMut};
4use saluki_core::pooling::{helpers::pooled_newtype, Clearable, ReclaimStrategy};
5use triomphe::{Arc as TriompheArc, UniqueArc};
6
7use super::{ClearableIoBuffer, CollapsibleReadWriteIoBuffer, ReadIoBuffer};
8
9pub struct FixedSizeVec {
17 data: UniqueArc<Vec<u8>>,
18 read_idx: usize,
19}
20
21impl FixedSizeVec {
22 pub fn with_capacity(capacity: usize) -> Self {
26 Self {
27 data: UniqueArc::new(Vec::with_capacity(capacity)),
28 read_idx: 0,
29 }
30 }
31
32 fn freeze(self) -> FrozenFixedSizeVec {
33 FrozenFixedSizeVec {
34 data: self.data.shareable(),
35 read_idx: self.read_idx,
36 }
37 }
38}
39
40impl Clearable for FixedSizeVec {
41 fn clear(&mut self) {
42 self.data.clear();
43 self.read_idx = 0;
44 }
45}
46
47struct FrozenFixedSizeVec {
48 data: TriompheArc<Vec<u8>>,
49 read_idx: usize,
50}
51
52impl FrozenFixedSizeVec {
53 fn into_unique(self) -> Option<FixedSizeVec> {
54 TriompheArc::into_unique(self.data).map(|data| FixedSizeVec { data, read_idx: 0 })
55 }
56}
57
58impl Clone for FrozenFixedSizeVec {
59 fn clone(&self) -> Self {
60 Self {
61 data: self.data.clone(),
62 read_idx: 0,
63 }
64 }
65}
66
67pooled_newtype! {
68 outer => BytesBuffer,
69 inner => FixedSizeVec,
70}
71
72impl BytesBuffer {
73 pub fn freeze(mut self) -> FrozenBytesBuffer {
75 let data = self.data.take().unwrap().freeze();
76
77 FrozenBytesBuffer {
78 strategy_ref: Arc::clone(&self.strategy_ref),
79 data: ManuallyDrop::new(data),
80 }
81 }
82}
83
84impl Buf for BytesBuffer {
85 fn remaining(&self) -> usize {
86 self.data().data.len() - self.data().read_idx
87 }
88
89 fn chunk(&self) -> &[u8] {
90 let data = self.data();
91 &data.data[data.read_idx..data.data.len()]
92 }
93
94 fn advance(&mut self, cnt: usize) {
95 let data = self.data_mut();
96 saluki_antithesis::always_le!(data.read_idx + cnt, data.data.len(), "buffer advance within bounds");
97 assert!(data.read_idx + cnt <= data.data.len());
98 data.read_idx += cnt;
99 }
100}
101
102unsafe impl BufMut for BytesBuffer {
103 fn remaining_mut(&self) -> usize {
104 let data = self.data();
105 data.data.capacity() - data.data.len()
106 }
107
108 fn chunk_mut(&mut self) -> &mut UninitSlice {
109 self.data_mut().data.spare_capacity_mut().into()
110 }
111
112 unsafe fn advance_mut(&mut self, cnt: usize) {
113 let new_len = self.data().data.len() + cnt;
114 self.data_mut().data.set_len(new_len);
115 }
116}
117
118impl ReadIoBuffer for BytesBuffer {
119 fn capacity(&self) -> usize {
120 self.data().data.capacity()
121 }
122}
123
124impl CollapsibleReadWriteIoBuffer for BytesBuffer {
125 fn collapse(&mut self) {
126 let remaining = self.remaining();
127
128 if remaining == 0 {
130 let inner = self.data_mut();
131 inner.read_idx = 0;
132 inner.data.clear();
133 return;
134 }
135
136 let inner = self.data_mut();
139
140 let src_start = inner.read_idx;
141 let src_end = inner.data.len();
142 inner.data.copy_within(src_start..src_end, 0);
143 inner.data.truncate(remaining);
144 inner.read_idx = 0;
145 }
146}
147
148impl ClearableIoBuffer for BytesBuffer {
149 fn clear(&mut self) {
150 self.data_mut().clear();
151 }
152}
153
154#[derive(Clone)]
165pub struct FrozenBytesBuffer {
166 strategy_ref: Arc<dyn ReclaimStrategy<BytesBuffer> + Send + Sync>,
167 data: ManuallyDrop<FrozenFixedSizeVec>,
168}
169
170impl FrozenBytesBuffer {
171 pub fn is_empty(&self) -> bool {
173 self.data.read_idx == self.data.data.len()
174 }
175
176 pub fn len(&self) -> usize {
178 self.data.data.len() - self.data.read_idx
179 }
180
181 pub fn capacity(&self) -> usize {
183 self.data.data.capacity()
184 }
185}
186
187impl Buf for FrozenBytesBuffer {
188 fn remaining(&self) -> usize {
189 self.data.data.len() - self.data.read_idx
190 }
191
192 fn chunk(&self) -> &[u8] {
193 &self.data.data[self.data.read_idx..]
194 }
195
196 fn advance(&mut self, cnt: usize) {
197 saluki_antithesis::always_le!(
198 self.data.read_idx + cnt,
199 self.data.data.len(),
200 "buffer advance within bounds"
201 );
202 assert!(self.data.read_idx + cnt <= self.data.data.len());
203 self.data.read_idx += cnt;
204 }
205}
206
207impl Drop for FrozenBytesBuffer {
208 fn drop(&mut self) {
209 let data = unsafe { ManuallyDrop::take(&mut self.data) };
214 if let Some(data) = data.into_unique() {
215 self.strategy_ref.reclaim(data);
216 }
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use saluki_core::pooling::helpers::get_pooled_object_via_builder;
223
224 use super::*;
225
226 #[test]
227 fn basic() {
228 let mut buf = get_pooled_object_via_builder::<_, BytesBuffer>(|| FixedSizeVec::with_capacity(13));
229
230 let first_write = b"hello";
231 let second_write = b", worl";
232 let third_write = b"d!";
233
234 assert_eq!(buf.remaining(), 0);
236 assert_eq!(buf.remaining_mut(), 13);
237
238 buf.put_slice(first_write);
240 assert_eq!(buf.remaining(), 5);
241 assert_eq!(buf.remaining_mut(), 8);
242
243 buf.put_slice(second_write);
245 assert_eq!(buf.remaining(), 11);
246 assert_eq!(buf.remaining_mut(), 2);
247
248 let first_chunk = buf.chunk();
250 assert_eq!(first_chunk.len(), 11);
251 assert_eq!(first_chunk, b"hello, worl");
252
253 buf.advance(7);
254 assert_eq!(buf.remaining(), 4);
255 assert_eq!(buf.remaining_mut(), 2);
256
257 buf.put_slice(third_write);
259 assert_eq!(buf.remaining(), 6);
260 assert_eq!(buf.remaining_mut(), 0);
261
262 let second_chunk = buf.chunk();
264 assert_eq!(second_chunk.len(), 6);
265 assert_eq!(second_chunk, b"world!");
266
267 buf.advance(6);
268 assert_eq!(buf.remaining(), 0);
269 assert_eq!(buf.remaining_mut(), 0);
270
271 buf.data_mut().clear();
273 assert_eq!(buf.remaining(), 0);
274 assert_eq!(buf.remaining_mut(), 13);
275 }
276
277 #[test]
278 fn collapsible_empty() {
279 let mut buf = get_pooled_object_via_builder::<_, BytesBuffer>(|| FixedSizeVec::with_capacity(13));
280
281 assert_eq!(buf.remaining(), 0);
283 assert_eq!(buf.remaining_mut(), 13);
284
285 buf.collapse();
286
287 assert_eq!(buf.remaining(), 0);
289 assert_eq!(buf.remaining_mut(), 13);
290 }
291
292 #[test]
293 fn collapsible_remaining_already_collapsed() {
294 let mut buf = get_pooled_object_via_builder::<_, BytesBuffer>(|| FixedSizeVec::with_capacity(24));
295
296 buf.put_slice(b"hello, world!");
298 assert_eq!(buf.remaining(), 13);
299 assert_eq!(buf.remaining_mut(), 11);
300
301 buf.collapse();
302
303 assert_eq!(buf.remaining(), 13);
305 assert_eq!(buf.remaining_mut(), 11);
306 }
307
308 #[test]
309 fn collapsible_remaining_not_collapsed_no_overlap() {
310 let mut buf = get_pooled_object_via_builder::<_, BytesBuffer>(|| FixedSizeVec::with_capacity(24));
311
312 buf.put_slice(b"hello, world!");
314 assert_eq!(buf.remaining(), 13);
315 assert_eq!(buf.remaining_mut(), 11);
316 assert_eq!(buf.chunk(), b"hello, world!");
317
318 buf.put_slice(b"huzzah!");
320 assert_eq!(buf.remaining(), 20);
321 assert_eq!(buf.remaining_mut(), 4);
322 assert_eq!(buf.chunk(), b"hello, world!huzzah!");
323
324 buf.advance(13);
327 assert_eq!(buf.remaining(), 7);
328 assert_eq!(buf.remaining_mut(), 4);
329 assert_eq!(buf.chunk(), b"huzzah!");
330
331 buf.collapse();
332
333 assert_eq!(buf.remaining(), 7);
335 assert_eq!(buf.remaining_mut(), 17);
336 assert_eq!(buf.chunk(), b"huzzah!");
337 }
338
339 #[test]
340 fn collapsible_remaining_not_collapsed_with_overlap() {
341 let mut buf = get_pooled_object_via_builder::<_, BytesBuffer>(|| FixedSizeVec::with_capacity(24));
342
343 buf.put_slice(b"huzzah!");
345 assert_eq!(buf.remaining(), 7);
346 assert_eq!(buf.remaining_mut(), 17);
347 assert_eq!(buf.chunk(), b"huzzah!");
348
349 buf.put_slice(b"hello, world!");
351 assert_eq!(buf.remaining(), 20);
352 assert_eq!(buf.remaining_mut(), 4);
353 assert_eq!(buf.chunk(), b"huzzah!hello, world!");
354
355 buf.advance(7);
358 assert_eq!(buf.remaining(), 13);
359 assert_eq!(buf.remaining_mut(), 4);
360 assert_eq!(buf.chunk(), b"hello, world!");
361
362 buf.collapse();
363
364 assert_eq!(buf.remaining(), 13);
366 assert_eq!(buf.remaining_mut(), 11);
367 assert_eq!(buf.chunk(), b"hello, world!");
368 }
369}