1use bytes::{Buf, Bytes, BytesMut};
2use std::collections::VecDeque;
3
4#[derive(Debug, Default)]
23pub struct SegmentedBuffer {
24 segs: VecDeque<Bytes>,
25 len: usize,
26}
27
28impl SegmentedBuffer {
29 #[must_use]
30 pub const fn new() -> Self {
31 Self {
32 segs: VecDeque::new(),
33 len: 0,
34 }
35 }
36
37 #[inline]
38 #[must_use]
39 pub const fn len(&self) -> usize {
40 self.len
41 }
42
43 #[inline]
44 #[must_use]
45 pub const fn is_empty(&self) -> bool {
46 self.len == 0
47 }
48
49 #[inline]
51 #[must_use]
52 pub fn front_chunk(&self) -> &[u8] {
53 self.segs.front().map_or(&[], Bytes::as_ref)
54 }
55
56 #[inline]
57 pub fn push(&mut self, bytes: Bytes) {
58 if bytes.is_empty() {
59 return;
60 }
61 self.len += bytes.len();
62 self.segs.push_back(bytes);
63 }
64
65 pub fn copy_prefix(&self, n: usize, dst: &mut [u8]) -> bool {
69 if n > self.len || dst.len() < n {
70 return false;
71 }
72
73 let mut remaining = n;
74 let mut out_off = 0;
75 for seg in &self.segs {
76 if remaining == 0 {
77 break;
78 }
79 let take = remaining.min(seg.len());
80 dst[out_off..out_off + take].copy_from_slice(&seg[..take]);
81 out_off += take;
82 remaining -= take;
83 }
84 true
85 }
86
87 pub fn advance(&mut self, mut n: usize) {
93 assert!(n <= self.len);
94 self.len -= n;
95
96 while n > 0 {
97 let Some(front) = self.segs.front_mut() else {
98 break;
99 };
100 if n < front.len() {
101 front.advance(n);
102 break;
103 }
104
105 n -= front.len();
106 self.segs.pop_front();
107 }
108 }
109
110 pub fn take_bytes(&mut self, n: usize) -> Option<Bytes> {
115 if n == 0 {
116 return Some(Bytes::new());
117 }
118 if n > self.len {
119 return None;
120 }
121
122 let Some(front) = self.segs.front_mut() else {
123 return None;
124 };
125
126 if front.len() >= n {
127 self.len -= n;
128 if front.len() == n {
129 let out = self.segs.pop_front();
130 return out;
131 }
132
133 let out = front.slice(..n);
134 front.advance(n);
135 if front.is_empty() {
136 self.segs.pop_front();
137 }
138 return Some(out);
139 }
140
141 let mut out = BytesMut::with_capacity(n);
143 let mut remaining = n;
144 while remaining > 0 {
145 let seg = self
146 .segs
147 .pop_front()
148 .expect("len check ensures segments exist");
149 let take = remaining.min(seg.len());
150 out.extend_from_slice(&seg[..take]);
151 remaining -= take;
152 self.len -= take;
153 if take < seg.len() {
154 let mut rest = seg;
155 rest.advance(take);
156 self.segs.push_front(rest);
157 }
158 }
159
160 Some(out.freeze())
161 }
162
163 #[inline]
168 pub fn take_bytes_after(&mut self, skip: usize, n: usize) -> Option<Bytes> {
169 let total = skip.checked_add(n)?;
170 if total > self.len {
171 return None;
172 }
173 Some(self.take_bytes_after_available(skip, n))
174 }
175
176 #[inline]
182 pub fn take_bytes_after_available(&mut self, skip: usize, n: usize) -> Bytes {
183 let total = skip.checked_add(n).expect("skip + n must not overflow");
184 assert!(total <= self.len);
185 if n == 0 {
186 self.advance(skip);
187 return Bytes::new();
188 }
189
190 let front = self.segs.front_mut().expect("non-empty buffer");
191 if front.len() >= total {
192 self.len -= total;
193 front.advance(skip);
194 let out = front.split_to(n);
195 if front.is_empty() {
196 self.segs.pop_front();
197 }
198 return out;
199 }
200
201 self.advance(skip);
202 self.take_bytes(n)
203 .expect("len check ensures requested bytes are available")
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use bytes::Bytes;
211
212 #[test]
213 fn take_bytes_after_slices_within_front_segment() {
214 let mut buf = SegmentedBuffer::new();
215 buf.push(Bytes::from_static(b"hhpayloadtail"));
216
217 let payload = buf.take_bytes_after(2, 7).unwrap();
218
219 assert_eq!(&payload[..], b"payload");
220 assert_eq!(buf.len(), 4);
221 assert_eq!(&buf.take_bytes(4).unwrap()[..], b"tail");
222 }
223
224 #[test]
225 fn take_bytes_after_falls_back_across_segments() {
226 let mut buf = SegmentedBuffer::new();
227 buf.push(Bytes::from_static(b"hhpay"));
228 buf.push(Bytes::from_static(b"loadtail"));
229
230 let payload = buf.take_bytes_after(2, 7).unwrap();
231
232 assert_eq!(&payload[..], b"payload");
233 assert_eq!(buf.len(), 4);
234 assert_eq!(&buf.take_bytes(4).unwrap()[..], b"tail");
235 }
236
237 #[test]
238 fn take_bytes_slices_single_segment_without_losing_remainder() {
239 let mut buf = SegmentedBuffer::new();
240 buf.push(Bytes::from_static(b"abcdef"));
241
242 let out = buf.take_bytes(2).unwrap();
243 assert_eq!(&out[..], b"ab");
244 assert_eq!(buf.len(), 4);
245
246 let rest = buf.take_bytes(4).unwrap();
247 assert_eq!(&rest[..], b"cdef");
248 assert!(buf.is_empty());
249 }
250
251 #[test]
252 fn take_bytes_removes_exact_single_segment() {
253 let mut buf = SegmentedBuffer::new();
254 buf.push(Bytes::from_static(b"abc"));
255
256 let out = buf.take_bytes(3).unwrap();
257 assert_eq!(&out[..], b"abc");
258 assert!(buf.is_empty());
259 }
260
261 #[test]
262 fn take_bytes_copies_across_segments_and_preserves_tail() {
263 let mut buf = SegmentedBuffer::new();
264 buf.push(Bytes::from_static(b"abc"));
265 buf.push(Bytes::from_static(b"def"));
266
267 let out = buf.take_bytes(4).unwrap();
268 assert_eq!(&out[..], b"abcd");
269 assert_eq!(buf.len(), 2);
270
271 let tail = buf.take_bytes(2).unwrap();
272 assert_eq!(&tail[..], b"ef");
273 assert!(buf.is_empty());
274 }
275}