1use std::{
10 cmp,
11 io::{self, Read, Write},
12 ops, ptr,
13 sync::atomic::{AtomicUsize, Ordering},
14};
15
16use crate::metrics::names;
17
18static BUFFER_COUNT: AtomicUsize = AtomicUsize::new(0);
19
20pub struct Pool {
21 pub inner: poule::Pool<BufferMetadata>,
22 pub buffer_size: usize,
23}
24
25impl Pool {
26 pub fn with_capacity(minimum: usize, maximum: usize, buffer_size: usize) -> Pool {
27 debug_assert!(
28 minimum <= maximum,
29 "pool minimum ({minimum}) must not exceed maximum ({maximum})"
30 );
31 let mut inner = poule::Pool::with_extra(maximum, buffer_size);
32 inner.grow_to(minimum);
33 let pool = Pool { inner, buffer_size };
34 debug_assert_eq!(pool.inner.used(), 0, "a fresh pool has nothing checked out");
38 debug_assert!(
39 pool.inner.capacity() <= maximum,
40 "grown capacity must never exceed the configured maximum"
41 );
42 #[cfg(debug_assertions)]
43 pool.check_invariants();
44 pool
45 }
46
47 pub fn checkout(&mut self) -> Option<Checkout> {
48 #[cfg(debug_assertions)]
50 self.check_invariants();
51 let used_before = self.inner.used();
55
56 if self.inner.used() == self.inner.capacity()
57 && self.inner.capacity() < self.inner.maximum_capacity()
58 {
59 self.inner.grow_to(std::cmp::min(
60 self.inner.capacity() * 2,
61 self.inner.maximum_capacity(),
62 ));
63 debug!(
64 "growing pool capacity from {} to {}",
65 self.inner.capacity(),
66 std::cmp::min(self.inner.capacity() * 2, self.inner.maximum_capacity())
67 );
68 }
69 let capacity = self.buffer_size;
70 let buffer_size = self.buffer_size;
71 let result = self
72 .inner
73 .checkout(|| {
74 trace!("initializing a buffer with capacity {}", capacity);
75 BufferMetadata::new()
76 })
77 .map(|c| {
78 let old_buffer_count = BUFFER_COUNT.fetch_add(1, Ordering::SeqCst);
79 gauge!(names::buffer::IN_USE, old_buffer_count + 1);
80 Checkout { inner: c }
81 });
82
83 match &result {
84 Some(checkout) => {
85 debug_assert_eq!(
88 self.inner.used(),
89 used_before + 1,
90 "a successful checkout must increment used-count by exactly 1"
91 );
92 debug_assert!(
93 self.inner.used() <= self.inner.capacity(),
94 "used-count must never exceed the pool capacity"
95 );
96 debug_assert!(
102 checkout.capacity() >= buffer_size,
103 "a checked-out buffer must hold at least the configured buffer size"
104 );
105 debug_assert_eq!(
106 checkout.available_data(),
107 0,
108 "a freshly checked-out buffer must hold no data"
109 );
110 }
111 None => {
112 debug_assert_eq!(
116 self.inner.used(),
117 used_before,
118 "a failed checkout must not change the used-count"
119 );
120 debug_assert_eq!(
121 self.inner.capacity(),
122 self.inner.maximum_capacity(),
123 "checkout only fails once the pool is grown to its maximum"
124 );
125 }
126 }
127
128 #[cfg(debug_assertions)]
130 self.check_invariants();
131 result
132 }
133
134 #[cfg(debug_assertions)]
142 fn check_invariants(&self) {
143 let used = self.inner.used();
144 let capacity = self.inner.capacity();
145 let maximum = self.inner.maximum_capacity();
146
147 debug_assert!(
150 used <= capacity,
151 "checked-out buffers ({used}) must never exceed live capacity ({capacity})"
152 );
153 let available = capacity - used;
154 debug_assert_eq!(
155 available + used,
156 capacity,
157 "available ({available}) + checked_out ({used}) must equal capacity ({capacity})"
158 );
159
160 debug_assert!(
162 capacity <= maximum,
163 "live capacity ({capacity}) must never exceed maximum_capacity ({maximum})"
164 );
165 }
166}
167
168impl ops::Deref for Pool {
169 type Target = poule::Pool<BufferMetadata>;
170
171 fn deref(&self) -> &Self::Target {
172 &self.inner
173 }
174}
175
176impl ops::DerefMut for Pool {
177 fn deref_mut(&mut self) -> &mut poule::Pool<BufferMetadata> {
178 &mut self.inner
179 }
180}
181
182#[derive(Debug, PartialEq, Eq, Clone)]
183pub struct BufferMetadata {
184 position: usize,
185 end: usize,
186}
187
188impl Default for BufferMetadata {
189 fn default() -> Self {
190 Self::new()
191 }
192}
193
194impl BufferMetadata {
195 pub fn new() -> BufferMetadata {
196 BufferMetadata {
197 position: 0,
198 end: 0,
199 }
200 }
201}
202
203pub struct Checkout {
204 pub inner: poule::Checkout<BufferMetadata>,
205}
206
207impl Drop for Checkout {
224 fn drop(&mut self) {
225 let old_buffer_count = BUFFER_COUNT.fetch_sub(1, Ordering::SeqCst);
226 debug_assert!(
233 old_buffer_count >= 1,
234 "buffer in-use gauge underflow on checkin: count was {old_buffer_count} before decrement"
235 );
236 gauge!(names::buffer::IN_USE, old_buffer_count - 1);
237 }
238}
239
240impl Checkout {
241 pub fn available_data(&self) -> usize {
242 self.inner.end - self.inner.position
243 }
244
245 pub fn available_space(&self) -> usize {
246 self.capacity() - self.inner.end
247 }
248
249 pub fn capacity(&self) -> usize {
250 self.inner.extra().len()
251 }
252
253 pub fn empty(&self) -> bool {
254 self.inner.position == self.inner.end
255 }
256
257 #[cfg(debug_assertions)]
262 fn check_invariants(&self) {
263 let position = self.inner.position;
264 let end = self.inner.end;
265 let capacity = self.capacity();
266 debug_assert!(
267 position <= end,
268 "buffer position ({position}) must not pass end ({end})"
269 );
270 debug_assert!(
271 end <= capacity,
272 "buffer end ({end}) must not exceed capacity ({capacity})"
273 );
274 debug_assert_eq!(
277 position + self.available_data() + self.available_space(),
278 capacity,
279 "consumed prefix + available data + free space must tile the whole buffer"
280 );
281 }
282
283 pub fn consume(&mut self, count: usize) -> usize {
284 #[cfg(debug_assertions)]
285 self.check_invariants();
286 let available_before = self.available_data();
287 let cnt = cmp::min(count, available_before);
288 debug_assert!(
291 cnt <= available_before,
292 "consume count ({cnt}) must not exceed available data ({available_before})"
293 );
294 self.inner.position += cnt;
295 if self.inner.position > self.capacity() / 2 {
296 self.shift();
298 }
299 debug_assert_eq!(
302 self.available_data(),
303 available_before - cnt,
304 "consume must shrink available data by exactly the consumed count"
305 );
306 #[cfg(debug_assertions)]
307 self.check_invariants();
308 cnt
309 }
310
311 pub fn fill(&mut self, count: usize) -> usize {
312 #[cfg(debug_assertions)]
313 self.check_invariants();
314 let data_before = self.available_data();
315 let space_before = self.available_space();
316 let cnt = cmp::min(count, space_before);
317 debug_assert!(
320 cnt <= space_before,
321 "fill count ({cnt}) must not exceed available space ({space_before})"
322 );
323 self.inner.end += cnt;
324 if self.available_space() < self.available_data() + cnt {
325 self.shift();
327 }
328 debug_assert_eq!(
331 self.available_data(),
332 data_before + cnt,
333 "fill must grow available data by exactly the filled count"
334 );
335 #[cfg(debug_assertions)]
336 self.check_invariants();
337 cnt
338 }
339
340 pub fn reset(&mut self) {
341 self.inner.position = 0;
342 self.inner.end = 0;
343 debug_assert_eq!(self.available_data(), 0, "reset must empty the buffer");
346 debug_assert_eq!(
347 self.available_space(),
348 self.capacity(),
349 "reset must restore the full capacity as free space"
350 );
351 #[cfg(debug_assertions)]
352 self.check_invariants();
353 }
354
355 pub fn sync(&mut self, end: usize, position: usize) {
356 debug_assert!(
361 position <= end,
362 "sync position ({position}) must not pass end ({end})"
363 );
364 debug_assert!(
365 end <= self.capacity(),
366 "sync end ({end}) must not exceed capacity ({})",
367 self.capacity()
368 );
369 self.inner.position = position;
370 self.inner.end = end;
371 debug_assert_eq!(
373 self.available_data(),
374 end - position,
375 "sync must expose exactly end - position readable bytes"
376 );
377 #[cfg(debug_assertions)]
378 self.check_invariants();
379 }
380
381 pub fn data(&self) -> &[u8] {
382 &self.inner.extra()[self.inner.position..self.inner.end]
383 }
384
385 pub fn space(&mut self) -> &mut [u8] {
386 let range = self.inner.end..self.capacity();
387 &mut self.inner.extra_mut()[range]
388 }
389
390 pub fn shift(&mut self) {
391 #[cfg(debug_assertions)]
392 self.check_invariants();
393 let pos = self.inner.position;
394 let end = self.inner.end;
395 let data_before = self.available_data();
396 if pos > 0 {
397 unsafe {
402 let length = end - pos;
403 ptr::copy(
404 self.inner.extra()[pos..end].as_ptr(),
405 self.inner.extra_mut()[..length].as_mut_ptr(),
406 length,
407 );
408 self.inner.position = 0;
409 self.inner.end = length;
410 }
411 }
412 debug_assert_eq!(
415 self.available_data(),
416 data_before,
417 "shift must preserve the amount of readable data"
418 );
419 #[cfg(debug_assertions)]
420 self.check_invariants();
421 }
422
423 pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
424 #[cfg(debug_assertions)]
425 self.check_invariants();
426 let data_before = self.available_data();
427 if start + length >= self.available_data() {
428 debug_assert_eq!(
430 self.available_data(),
431 data_before,
432 "rejected delete_slice must not mutate the buffer"
433 );
434 return None;
435 }
436
437 unsafe {
443 let begin = self.inner.position + start;
444 let next_end = self.inner.end - length;
445 ptr::copy(
446 self.inner.extra()[begin + length..self.inner.end].as_ptr(),
447 self.inner.extra_mut()[begin..next_end].as_mut_ptr(),
448 self.inner.end - (begin + length),
449 );
450 self.inner.end = next_end;
451 }
452 debug_assert_eq!(
455 self.available_data(),
456 data_before - length,
457 "delete_slice must shrink available data by exactly the deleted length"
458 );
459 #[cfg(debug_assertions)]
460 self.check_invariants();
461 Some(self.available_data())
462 }
463
464 pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
465 #[cfg(debug_assertions)]
466 self.check_invariants();
467 let data_before = self.available_data();
468 let data_len = data.len();
469 if start + length > self.available_data()
470 || self.inner.position + start + data_len > self.capacity()
471 {
472 debug_assert_eq!(
474 self.available_data(),
475 data_before,
476 "rejected replace_slice must not mutate the buffer"
477 );
478 return None;
479 }
480 debug_assert!(
484 start + length <= data_before,
485 "replace_slice window [{start}, {}) must lie within available data ({data_before})",
486 start + length
487 );
488
489 unsafe {
496 let begin = self.inner.position + start;
497 let slice_end = begin + data_len;
498 if data_len < length {
500 ptr::copy(
501 data.as_ptr(),
502 self.inner.extra_mut()[begin..slice_end].as_mut_ptr(),
503 data_len,
504 );
505
506 ptr::copy(
507 self.inner.extra()[start + length..self.inner.end].as_ptr(),
508 self.inner.extra_mut()[slice_end..].as_mut_ptr(),
509 self.inner.end - (start + length),
510 );
511 self.inner.end -= length - data_len;
512
513 } else {
515 ptr::copy(
516 self.inner.extra()[start + length..self.inner.end].as_ptr(),
517 self.inner.extra_mut()[start + data_len..].as_mut_ptr(),
518 self.inner.end - (start + length),
519 );
520 ptr::copy(
521 data.as_ptr(),
522 self.inner.extra_mut()[begin..slice_end].as_mut_ptr(),
523 data_len,
524 );
525 self.inner.end += data_len - length;
526 }
527 }
528 debug_assert_eq!(
533 self.available_data() as i64,
534 data_before as i64 + data_len as i64 - length as i64,
535 "replace_slice must change available data by exactly data_len - length"
536 );
537 #[cfg(debug_assertions)]
538 self.check_invariants();
539 Some(self.available_data())
540 }
541
542 pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
543 #[cfg(debug_assertions)]
544 self.check_invariants();
545 let data_before = self.available_data();
546 let data_len = data.len();
547 if start > self.available_data()
548 || self.inner.position + self.inner.end + data_len > self.capacity()
549 {
550 debug_assert_eq!(
552 self.available_data(),
553 data_before,
554 "rejected insert_slice must not mutate the buffer"
555 );
556 return None;
557 }
558 debug_assert!(
561 start <= data_before,
562 "insert_slice start ({start}) must lie within available data ({data_before})"
563 );
564
565 unsafe {
571 let begin = self.inner.position + start;
572 let slice_end = begin + data_len;
573 ptr::copy(
574 self.inner.extra()[start..self.inner.end].as_ptr(),
575 self.inner.extra_mut()[start + data_len..].as_mut_ptr(),
576 self.inner.end - start,
577 );
578 ptr::copy(
579 data.as_ptr(),
580 self.inner.extra_mut()[begin..slice_end].as_mut_ptr(),
581 data_len,
582 );
583 self.inner.end += data_len;
584 }
585 debug_assert_eq!(
588 self.available_data(),
589 data_before + data_len,
590 "insert_slice must grow available data by exactly the inserted length"
591 );
592 #[cfg(debug_assertions)]
593 self.check_invariants();
594 Some(self.available_data())
595 }
596}
597
598impl Write for Checkout {
599 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
600 match self.space().write(buf) {
601 Ok(size) => {
602 self.fill(size);
603 Ok(size)
604 }
605 err => err,
606 }
607 }
608
609 fn flush(&mut self) -> io::Result<()> {
610 Ok(())
611 }
612}
613
614impl Read for Checkout {
615 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
616 let len = cmp::min(self.available_data(), buf.len());
617 unsafe {
623 ptr::copy(
624 self.inner.extra()[self.inner.position..self.inner.position + len].as_ptr(),
625 buf.as_mut_ptr(),
626 len,
627 );
628 self.inner.position += len;
629 }
630 Ok(len)
631 }
632}
633
634#[cfg(test)]
635mod tests {
636 use super::*;
637 use std::io::{Read, Write};
638
639 fn create_test_pool(buffer_size: usize, max_count: usize) -> Pool {
641 Pool::with_capacity(max_count, max_count, buffer_size)
642 }
643
644 fn checkout_with_data(pool: &mut Pool, data: &[u8]) -> Checkout {
646 let mut buf = pool.checkout().expect("checkout should succeed");
647 let n = buf.write(data).expect("write should succeed");
648 assert_eq!(n, data.len(), "all bytes should be written");
649 buf
650 }
651
652 #[test]
657 fn test_pool_checkout_returns_buffer() {
658 let mut pool = create_test_pool(1024, 2);
659 let buf = pool.checkout();
660 assert!(
661 buf.is_some(),
662 "first checkout from a fresh pool must succeed"
663 );
664 let buf = buf.unwrap();
665 assert_eq!(buf.capacity(), 1024);
666 assert_eq!(buf.available_data(), 0);
667 assert_eq!(buf.available_space(), 1024);
668 }
669
670 #[test]
671 fn test_pool_checkin_on_drop() {
672 let mut pool = create_test_pool(128, 1);
673 {
674 let _buf = pool.checkout().expect("checkout should succeed");
675 assert_eq!(pool.inner.used(), 1);
676 }
677 assert_eq!(pool.inner.used(), 0);
678 let buf2 = pool.checkout();
679 assert!(buf2.is_some(), "checkout after checkin should succeed");
680 }
681
682 #[test]
683 fn test_pool_auto_grow() {
684 let mut pool = Pool::with_capacity(1, 4, 256);
685 let _b1 = pool.checkout().expect("first checkout");
686 let _b2 = pool.checkout().expect("second checkout triggers growth");
687 let _b3 = pool.checkout().expect("third checkout");
688 }
689
690 #[test]
695 fn test_checkout_write_and_read_data() {
696 let mut pool = create_test_pool(1024, 2);
697 let mut buf = pool.checkout().unwrap();
698
699 let payload = b"hello world";
700 let written = buf.write(payload).unwrap();
701 assert_eq!(written, payload.len());
702 assert_eq!(buf.available_data(), payload.len());
703 assert_eq!(buf.data(), payload);
704 }
705
706 #[test]
707 fn test_checkout_read_trait() {
708 let mut pool = create_test_pool(1024, 2);
709 let mut buf = checkout_with_data(&mut pool, b"hello");
710
711 let mut out = [0u8; 5];
712 let n = buf.read(&mut out).unwrap();
713 assert_eq!(n, 5);
714 assert_eq!(&out, b"hello");
715 }
716
717 #[test]
718 fn test_consume_and_fill() {
719 let mut pool = create_test_pool(1024, 2);
720 let mut buf = checkout_with_data(&mut pool, b"abcdefghij");
721
722 let consumed = buf.consume(3);
723 assert_eq!(consumed, 3);
724 assert_eq!(buf.data(), b"defghij");
725 assert_eq!(buf.available_data(), 7);
726
727 let filled = buf.fill(0);
728 assert_eq!(filled, 0);
729 }
730
731 #[test]
732 fn test_empty() {
733 let mut pool = create_test_pool(64, 2);
734 let buf = pool.checkout().unwrap();
735 assert!(buf.empty(), "freshly checked-out buffer should be empty");
736 }
737
738 #[test]
739 fn test_reset() {
740 let mut pool = create_test_pool(1024, 2);
741 let mut buf = checkout_with_data(&mut pool, b"data");
742 assert!(!buf.empty());
743
744 buf.reset();
745 assert!(buf.empty());
746 assert_eq!(buf.available_data(), 0);
747 }
748
749 #[test]
750 fn test_sync() {
751 let mut pool = create_test_pool(1024, 2);
752 let mut buf = checkout_with_data(&mut pool, b"hello world");
753 buf.sync(5, 2);
754 assert_eq!(buf.available_data(), 3);
755 }
756
757 #[test]
762 fn test_shift_moves_data_to_start() {
763 let mut pool = create_test_pool(1024, 2);
764 let mut buf = checkout_with_data(&mut pool, b"hello world");
765
766 buf.inner.position = 5;
767 assert_eq!(buf.data(), b" world");
768
769 buf.shift();
770 assert_eq!(buf.inner.position, 0);
771 assert_eq!(buf.inner.end, 6);
772 assert_eq!(buf.data(), b" world");
773 }
774
775 #[test]
776 fn test_shift_noop_when_position_zero() {
777 let mut pool = create_test_pool(1024, 2);
778 let mut buf = checkout_with_data(&mut pool, b"hello");
779
780 assert_eq!(buf.inner.position, 0);
781 buf.shift();
782 assert_eq!(buf.data(), b"hello");
783 assert_eq!(buf.inner.position, 0);
784 assert_eq!(buf.inner.end, 5);
785 }
786
787 #[test]
788 fn test_consume_triggers_auto_shift() {
789 let mut pool = create_test_pool(256, 2);
790 let mut buf = pool.checkout().unwrap();
791 let capacity = buf.capacity();
792
793 let fill_count = capacity / 2 + 2;
794 let data: Vec<u8> = (0..fill_count as u8).collect();
795 let written = buf.write(&data).unwrap();
796 assert_eq!(written, fill_count);
797
798 let consume_count = capacity / 2 + 1;
799 buf.consume(consume_count);
800
801 assert_eq!(buf.inner.position, 0);
802 let remaining = fill_count - consume_count;
803 assert_eq!(buf.available_data(), remaining);
804 }
805
806 #[test]
811 fn test_delete_slice_middle() {
812 let mut pool = create_test_pool(1024, 2);
813 let mut buf = checkout_with_data(&mut pool, b"hello world!");
814
815 let result = buf.delete_slice(3, 5);
816 assert!(result.is_some());
817 assert_eq!(buf.data(), b"helrld!");
818 }
819
820 #[test]
821 fn test_delete_slice_from_start() {
822 let mut pool = create_test_pool(1024, 2);
823 let mut buf = checkout_with_data(&mut pool, b"hello world!");
824
825 let result = buf.delete_slice(0, 3);
826 assert!(result.is_some());
827 assert_eq!(buf.data(), b"lo world!");
828 }
829
830 #[test]
831 fn test_delete_slice_near_end() {
832 let mut pool = create_test_pool(1024, 2);
833 let mut buf = checkout_with_data(&mut pool, b"hello world!");
834
835 let result = buf.delete_slice(7, 4);
836 assert!(result.is_some());
837 assert_eq!(buf.data(), b"hello w!");
838 }
839
840 #[test]
841 fn test_delete_slice_out_of_bounds_returns_none() {
842 let mut pool = create_test_pool(1024, 2);
843 let mut buf = checkout_with_data(&mut pool, b"hello");
844
845 let result = buf.delete_slice(0, 5);
846 assert!(result.is_none());
847
848 let result = buf.delete_slice(3, 5);
849 assert!(result.is_none());
850 }
851
852 #[test]
853 fn test_delete_slice_single_byte() {
854 let mut pool = create_test_pool(1024, 2);
855 let mut buf = checkout_with_data(&mut pool, b"abcd");
856
857 let result = buf.delete_slice(1, 1);
858 assert!(result.is_some());
859 assert_eq!(buf.data(), b"acd");
860 }
861
862 #[test]
867 fn test_replace_slice_same_size() {
868 let mut pool = create_test_pool(1024, 2);
869 let mut buf = checkout_with_data(&mut pool, b"hello world");
870
871 let result = buf.replace_slice(b"earth", 6, 5);
872 assert!(result.is_some());
873 assert_eq!(buf.data(), b"hello earth");
874 }
875
876 #[test]
877 fn test_replace_slice_shrink() {
878 let mut pool = create_test_pool(1024, 2);
879 let mut buf = checkout_with_data(&mut pool, b"hello world");
880
881 let result = buf.replace_slice(b"hi", 6, 5);
882 assert!(result.is_some());
883 assert_eq!(buf.data(), b"hello hi");
884 }
885
886 #[test]
887 fn test_replace_slice_grow() {
888 let mut pool = create_test_pool(1024, 2);
889 let mut buf = checkout_with_data(&mut pool, b"hello world");
890
891 let result = buf.replace_slice(b"universe", 6, 5);
892 assert!(result.is_some());
893 assert_eq!(buf.data(), b"hello universe");
894 }
895
896 #[test]
897 fn test_replace_slice_at_start() {
898 let mut pool = create_test_pool(1024, 2);
899 let mut buf = checkout_with_data(&mut pool, b"hello world");
900
901 let result = buf.replace_slice(b"hey", 0, 5);
902 assert!(result.is_some());
903 assert_eq!(buf.data(), b"hey world");
904 }
905
906 #[test]
907 fn test_replace_slice_out_of_bounds_returns_none() {
908 let mut pool = create_test_pool(1024, 2);
909 let mut buf = checkout_with_data(&mut pool, b"hello");
910
911 let result = buf.replace_slice(b"x", 4, 5);
912 assert!(result.is_none());
913 }
914
915 #[test]
916 fn test_replace_slice_exceeds_data_bounds_returns_none() {
917 let mut pool = create_test_pool(256, 2);
918 let mut buf = checkout_with_data(&mut pool, b"hello");
919
920 let result = buf.replace_slice(b"xyz", 3, 5);
921 assert!(result.is_none());
922 }
923
924 #[test]
925 fn test_replace_slice_replacement_exceeds_capacity_returns_none() {
926 let mut pool = create_test_pool(256, 2);
927 let mut buf = pool.checkout().unwrap();
928 let capacity = buf.capacity();
929
930 let data = vec![b'x'; capacity];
931 let written = buf.write(&data).unwrap();
932 assert_eq!(written, capacity);
933
934 buf.inner.position = capacity - 2;
935 assert_eq!(buf.available_data(), 2);
936
937 let result = buf.replace_slice(b"abcde", 0, 1);
939 assert!(result.is_none());
940 }
941
942 #[test]
947 fn test_insert_slice_at_start() {
948 let mut pool = create_test_pool(1024, 2);
949 let mut buf = checkout_with_data(&mut pool, b"world");
950
951 let result = buf.insert_slice(b"hello ", 0);
952 assert!(result.is_some());
953 assert_eq!(buf.data(), b"hello world");
954 }
955
956 #[test]
957 fn test_insert_slice_in_middle() {
958 let mut pool = create_test_pool(1024, 2);
959 let mut buf = checkout_with_data(&mut pool, b"helo");
960
961 let result = buf.insert_slice(b"l", 2);
962 assert!(result.is_some());
963 assert_eq!(buf.data(), b"hello");
964 }
965
966 #[test]
967 fn test_insert_slice_at_end() {
968 let mut pool = create_test_pool(1024, 2);
969 let mut buf = checkout_with_data(&mut pool, b"hello");
970
971 let result = buf.insert_slice(b" world", 5);
972 assert!(result.is_some());
973 assert_eq!(buf.data(), b"hello world");
974 }
975
976 #[test]
977 fn test_insert_slice_exceeds_capacity_returns_none() {
978 let mut pool = create_test_pool(256, 2);
979 let mut buf = pool.checkout().unwrap();
980 let capacity = buf.capacity();
981
982 let data = vec![b'x'; capacity];
983 let written = buf.write(&data).unwrap();
984 assert_eq!(written, capacity);
985 assert_eq!(buf.available_space(), 0);
986
987 let result = buf.insert_slice(b"y", 0);
988 assert!(result.is_none());
989 }
990
991 #[test]
992 fn test_insert_slice_beyond_data_returns_none() {
993 let mut pool = create_test_pool(1024, 2);
994 let mut buf = checkout_with_data(&mut pool, b"hello");
995
996 let result = buf.insert_slice(b"x", 6);
997 assert!(result.is_none());
998 }
999
1000 #[test]
1005 fn test_write_consume_shift_write_again() {
1006 let mut pool = create_test_pool(32, 2);
1007 let mut buf = checkout_with_data(&mut pool, b"first");
1008
1009 buf.consume(5);
1010 assert_eq!(buf.available_data(), 0);
1011
1012 let n = buf.write(b"second").unwrap();
1013 assert_eq!(n, 6);
1014 assert_eq!(buf.data(), b"second");
1015 }
1016
1017 #[test]
1018 fn test_delete_then_insert() {
1019 let mut pool = create_test_pool(1024, 2);
1020 let mut buf = checkout_with_data(&mut pool, b"hello cruel world");
1021
1022 buf.delete_slice(6, 6);
1023 assert_eq!(buf.data(), b"hello world");
1024
1025 buf.insert_slice(b"beautiful ", 6);
1026 assert_eq!(buf.data(), b"hello beautiful world");
1027 }
1028
1029 #[test]
1030 fn test_multiple_replace_operations() {
1031 let mut pool = create_test_pool(1024, 2);
1032 let mut buf = checkout_with_data(&mut pool, b"aXbXc");
1033
1034 buf.replace_slice(b"12", 1, 1);
1035 assert_eq!(buf.data(), b"a12bXc");
1036
1037 buf.replace_slice(b"34", 4, 1);
1038 assert_eq!(buf.data(), b"a12b34c");
1039 }
1040}