nexus_net/buf/
read_buf.rs1pub struct ReadBuf {
44 buf: Box<[u8]>,
45 head: usize,
46 tail: usize,
47 capacity: usize,
48 pre_padding: usize,
49}
50
51impl ReadBuf {
52 #[must_use]
57 pub fn new(capacity: usize, pre_padding: usize, post_padding: usize) -> Self {
58 let total = pre_padding + capacity + post_padding;
59 Self {
60 buf: vec![0u8; total].into_boxed_slice(),
61 head: pre_padding,
62 tail: pre_padding,
63 capacity,
64 pre_padding,
65 }
66 }
67
68 #[must_use]
70 pub fn with_capacity(capacity: usize) -> Self {
71 Self::new(capacity, 0, 0)
72 }
73
74 #[inline]
80 pub fn data(&self) -> &[u8] {
81 &self.buf[self.head..self.tail]
82 }
83
84 #[inline]
87 pub fn data_mut(&mut self) -> &mut [u8] {
88 &mut self.buf[self.head..self.tail]
89 }
90
91 #[inline]
99 pub fn advance(&mut self, n: usize) {
100 if n > self.len() {
101 Self::panic_advance(n, self.len());
102 }
103 self.head += n;
104 if self.head == self.tail {
105 self.head = self.pre_padding;
106 self.tail = self.pre_padding;
107 }
108 }
109
110 #[inline]
124 pub fn spare(&mut self) -> &mut [u8] {
125 let end = self.pre_padding + self.capacity;
126 &mut self.buf[self.tail..end]
127 }
128
129 #[inline]
134 pub fn filled(&mut self, n: usize) {
135 let new_tail = self.tail + n;
136 let end = self.pre_padding + self.capacity;
137 if new_tail > end {
138 Self::panic_filled(n, self.tail, end);
139 }
140 self.tail = new_tail;
141 }
142
143 #[inline]
156 pub fn pre_padding_mut(&mut self) -> &mut [u8] {
157 &mut self.buf[..self.head]
158 }
159
160 #[inline]
166 pub fn len(&self) -> usize {
167 self.tail - self.head
168 }
169
170 #[inline]
172 pub fn is_empty(&self) -> bool {
173 self.head == self.tail
174 }
175
176 #[inline]
178 pub fn capacity(&self) -> usize {
179 self.capacity
180 }
181
182 #[inline]
184 pub fn remaining(&self) -> usize {
185 self.pre_padding + self.capacity - self.tail
186 }
187
188 pub fn clear(&mut self) {
190 self.head = self.pre_padding;
191 self.tail = self.pre_padding;
192 }
193
194 #[inline]
198 pub fn consumed(&self) -> usize {
199 self.head - self.pre_padding
200 }
201
202 pub fn compact(&mut self) {
213 if self.head <= self.pre_padding || self.head == self.tail {
214 return; }
216 let len = self.tail - self.head;
217 self.buf.copy_within(self.head..self.tail, self.pre_padding);
218 self.head = self.pre_padding;
219 self.tail = self.pre_padding + len;
220 }
221
222 #[cold]
223 #[inline(never)]
224 fn panic_advance(n: usize, len: usize) -> ! {
225 panic!("advance({n}) exceeds buffered data ({len})")
226 }
227
228 #[cold]
229 #[inline(never)]
230 fn panic_filled(n: usize, tail: usize, end: usize) -> ! {
231 panic!("filled({n}) would exceed capacity (tail={tail}, end={end})")
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn new_allocation_size() {
241 let buf = ReadBuf::new(100, 16, 4);
242 assert_eq!(buf.buf.len(), 120);
243 assert_eq!(buf.capacity(), 100);
244 assert_eq!(buf.len(), 0);
245 assert_eq!(buf.remaining(), 100);
246 }
247
248 #[test]
249 fn with_capacity_zero_padding() {
250 let buf = ReadBuf::with_capacity(4096);
251 assert_eq!(buf.capacity(), 4096);
252 assert_eq!(buf.buf.len(), 4096); assert_eq!(buf.remaining(), 4096);
254 assert_eq!(buf.pre_padding, 0);
255 }
256
257 #[test]
258 fn spare_filled_data() {
259 let mut buf = ReadBuf::with_capacity(64);
260 buf.spare()[..5].copy_from_slice(b"Hello");
261 buf.filled(5);
262 assert_eq!(buf.data(), b"Hello");
263 assert_eq!(buf.len(), 5);
264 assert_eq!(buf.remaining(), 59);
265 }
266
267 #[test]
268 fn advance_consumes() {
269 let mut buf = ReadBuf::with_capacity(64);
270 buf.spare()[..10].copy_from_slice(b"HelloWorld");
271 buf.filled(10);
272 buf.advance(5);
273 assert_eq!(buf.data(), b"World");
274 assert_eq!(buf.len(), 5);
275 }
276
277 #[test]
278 fn advance_auto_reset() {
279 let mut buf = ReadBuf::with_capacity(64);
280 buf.spare()[..5].copy_from_slice(b"Hello");
281 buf.filled(5);
282 buf.advance(5);
283 assert!(buf.is_empty());
284 assert_eq!(buf.remaining(), 64);
285 }
286
287 #[test]
288 fn data_mut_in_place() {
289 let mut buf = ReadBuf::with_capacity(64);
290 buf.spare()[..4].copy_from_slice(&[0x00, 0x01, 0x02, 0x03]);
291 buf.filled(4);
292 for b in buf.data_mut().iter_mut() {
293 *b ^= 0xFF;
294 }
295 assert_eq!(buf.data(), &[0xFF, 0xFE, 0xFD, 0xFC]);
296 }
297
298 #[test]
299 fn pre_padding_mut_accessible() {
300 let mut buf = ReadBuf::new(64, 16, 4);
301 buf.spare()[..5].copy_from_slice(b"World");
302 buf.filled(5);
303
304 let padding = buf.pre_padding_mut();
306 assert_eq!(padding.len(), 16);
307
308 padding[12..16].copy_from_slice(b"Hdr:");
310
311 buf.advance(3);
313 assert_eq!(buf.pre_padding_mut().len(), 19); }
315
316 #[test]
317 fn pre_padding_mut_after_advance() {
318 let mut buf = ReadBuf::new(64, 8, 0);
319 buf.spare()[..10].copy_from_slice(b"0123456789");
320 buf.filled(10);
321 buf.advance(5);
322
323 let padding = buf.pre_padding_mut();
325 assert_eq!(padding.len(), 13);
326 }
327
328 #[test]
329 fn remaining_tracks() {
330 let mut buf = ReadBuf::with_capacity(32);
331 assert_eq!(buf.remaining(), 32);
332 buf.spare()[..10].copy_from_slice(&[0; 10]);
333 buf.filled(10);
334 assert_eq!(buf.remaining(), 22);
335 buf.advance(10);
336 assert_eq!(buf.remaining(), 32); }
338
339 #[test]
340 fn clear_resets() {
341 let mut buf = ReadBuf::with_capacity(64);
342 buf.spare()[..10].copy_from_slice(&[0; 10]);
343 buf.filled(10);
344 buf.clear();
345 assert!(buf.is_empty());
346 assert_eq!(buf.remaining(), 64);
347 }
348
349 #[test]
350 fn spare_when_full() {
351 let mut buf = ReadBuf::with_capacity(8);
352 buf.spare()[..8].copy_from_slice(&[0; 8]);
353 buf.filled(8);
354 assert!(buf.spare().is_empty());
355 assert_eq!(buf.remaining(), 0);
356 }
357
358 #[test]
359 fn zero_length_operations() {
360 let mut buf = ReadBuf::with_capacity(32);
361 buf.filled(0);
362 assert!(buf.is_empty());
363 buf.advance(0);
364 assert!(buf.is_empty());
365 }
366
367 #[test]
368 fn large_capacity_smoke() {
369 let mut buf = ReadBuf::with_capacity(256 * 1024);
370 let data: Vec<u8> = (0..1024).map(|i| (i & 0xFF) as u8).collect();
371 buf.spare()[..1024].copy_from_slice(&data);
372 buf.filled(1024);
373 assert_eq!(buf.data(), data.as_slice());
374 buf.advance(512);
375 assert_eq!(buf.data(), &data[512..]);
376 buf.advance(512);
377 assert!(buf.is_empty());
378 assert_eq!(buf.remaining(), 256 * 1024);
379 }
380
381 #[test]
382 fn multiple_write_advance_cycles() {
383 let mut buf = ReadBuf::with_capacity(32);
384 for i in 0u8..10 {
385 buf.spare()[..4].copy_from_slice(&[i; 4]);
386 buf.filled(4);
387 assert_eq!(buf.data(), &[i; 4]);
388 buf.advance(4);
389 assert!(buf.is_empty());
390 }
391 }
392
393 #[test]
394 #[should_panic(expected = "advance")]
395 fn advance_exceeds_data() {
396 let mut buf = ReadBuf::with_capacity(32);
397 buf.spare()[..5].copy_from_slice(b"Hello");
398 buf.filled(5);
399 buf.advance(10);
400 }
401
402 #[test]
403 #[should_panic(expected = "filled")]
404 fn filled_exceeds_capacity() {
405 let mut buf = ReadBuf::with_capacity(8);
406 buf.filled(16);
407 }
408
409 #[test]
410 fn partial_advance_then_fill() {
411 let mut buf = ReadBuf::with_capacity(32);
412 buf.spare()[..10].copy_from_slice(b"0123456789");
413 buf.filled(10);
414 buf.advance(5);
415 assert_eq!(buf.data(), b"56789");
416
417 buf.spare()[..3].copy_from_slice(b"ABC");
418 buf.filled(3);
419 assert_eq!(buf.data(), b"56789ABC");
420 }
421
422 #[test]
423 fn head_drift_and_compact() {
424 let mut buf = ReadBuf::with_capacity(32);
425
426 buf.spare()[..20].copy_from_slice(&[0xAA; 20]);
428 buf.filled(20);
429
430 buf.advance(15);
432 assert_eq!(buf.len(), 5);
433 assert_eq!(buf.remaining(), 12);
434
435 buf.spare()[..12].copy_from_slice(&[0xBB; 12]);
437 buf.filled(12);
438 assert_eq!(buf.remaining(), 0); assert_eq!(buf.len(), 17);
440
441 buf.advance(10);
443 assert_eq!(buf.len(), 7);
444 assert_eq!(buf.remaining(), 0); assert!(buf.spare().is_empty());
448
449 buf.compact();
451 assert_eq!(buf.len(), 7); assert_eq!(buf.remaining(), 25); assert_eq!(&buf.data()[..5], &[0xBB; 5]); }
457
458 #[test]
459 fn compact_noop_when_at_front() {
460 let mut buf = ReadBuf::with_capacity(32);
461 buf.spare()[..10].copy_from_slice(&[0x42; 10]);
462 buf.filled(10);
463 buf.compact();
465 assert_eq!(buf.len(), 10);
466 assert_eq!(buf.remaining(), 22);
467 }
468
469 #[test]
470 fn compact_noop_when_empty() {
471 let mut buf = ReadBuf::with_capacity(32);
472 buf.compact(); assert_eq!(buf.remaining(), 32);
474 }
475
476 #[test]
477 fn with_padding_smoke() {
478 let mut buf = ReadBuf::new(64, 16, 32);
479 assert_eq!(buf.buf.len(), 112); assert_eq!(buf.capacity(), 64);
481 assert_eq!(buf.remaining(), 64);
482
483 buf.spare()[..10].copy_from_slice(b"0123456789");
484 buf.filled(10);
485 assert_eq!(buf.data(), b"0123456789");
486 }
487}