1use super::{
10 owner::{HeapOwner, OwnerRef, PooledBuffer},
11 panic_advance,
12 pool::BufferPool,
13};
14use bytes::{Buf, BufMut, Bytes, BytesMut, TryGetError};
15use commonware_codec::{BufsMut, EncodeSize, Error, RangeCfg, Read, Write, util::at_least};
16use std::{
17 mem::ManuallyDrop,
18 num::NonZeroUsize,
19 ops::{Bound, RangeBounds},
20 ptr::NonNull,
21};
22
23pub struct IoBuf {
46 ptr: NonNull<u8>,
47 len: usize,
48 owner: OwnerRef,
49}
50
51unsafe impl Send for IoBuf {}
54unsafe impl Sync for IoBuf {}
56
57impl std::fmt::Debug for IoBuf {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("IoBuf")
62 .field("len", &self.len)
63 .field("pooled", &self.is_pooled())
64 .finish()
65 }
66}
67
68impl Clone for IoBuf {
69 #[inline]
70 fn clone(&self) -> Self {
71 unsafe { self.owner.clone_shared() };
74 Self {
75 ptr: self.ptr,
76 len: self.len,
77 owner: self.owner,
78 }
79 }
80}
81
82impl Drop for IoBuf {
83 #[inline]
84 fn drop(&mut self) {
85 unsafe { self.owner.drop_shared() };
88 }
89}
90
91impl IoBuf {
92 pub fn copy_from_slice(data: &[u8]) -> Self {
100 IoBufMut::from(data).freeze()
101 }
102
103 #[inline]
104 fn from_static(slice: &'static [u8]) -> Self {
105 if slice.is_empty() {
106 return Self::default();
107 }
108 let ptr = NonNull::new(slice.as_ptr().cast_mut()).expect("static slice data is non-null");
109 Self {
110 ptr,
111 len: slice.len(),
112 owner: OwnerRef::empty(),
113 }
114 }
115
116 #[inline]
118 pub fn is_pooled(&self) -> bool {
119 self.owner.is_pooled()
120 }
121
122 #[inline]
124 pub const fn len(&self) -> usize {
125 self.len
126 }
127
128 #[inline]
130 pub const fn is_empty(&self) -> bool {
131 self.len == 0
132 }
133
134 #[inline]
136 pub const fn as_ptr(&self) -> *const u8 {
137 self.ptr.as_ptr()
138 }
139
140 #[inline]
150 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
151 let (start, end) = resolve_range(self.len, range);
152 if start == end {
153 return Self::default();
154 }
155
156 let ptr = unsafe { self.ptr.add(start) };
158 unsafe { self.owner.clone_shared() };
161 Self {
162 ptr,
163 len: end - start,
164 owner: self.owner,
165 }
166 }
167
168 pub fn split_to(&mut self, at: usize) -> Self {
180 assert!(
181 at <= self.len,
182 "split_to out of bounds: {:?} <= {:?}",
183 at,
184 self.len,
185 );
186 if at == 0 {
187 return Self::default();
188 }
189 if at == self.len {
190 return std::mem::take(self);
191 }
192
193 unsafe { self.owner.clone_shared() };
195 let prefix = Self {
196 ptr: self.ptr,
197 len: at,
198 owner: self.owner,
199 };
200 unsafe {
202 self.ptr = self.ptr.add(at);
203 }
204 self.len -= at;
205 prefix
206 }
207
208 pub fn try_into_mut(self) -> Result<IoBufMut, Self> {
221 if self.owner.is_empty() {
222 return if self.len == 0 {
223 Ok(IoBufMut::default())
224 } else {
225 Err(self)
226 };
227 }
228
229 if self.owner.is_external() {
232 return Err(self);
233 }
234
235 if !unsafe { self.owner.is_unique() } {
237 return Err(self);
238 }
239
240 let me = ManuallyDrop::new(self);
241 let base = unsafe { me.owner.data_base() };
243 let usable_capacity = unsafe { me.owner.usable_capacity() };
245 let offset = (me.ptr.as_ptr() as usize)
246 .checked_sub(base.as_ptr() as usize)
247 .expect("view pointer must be within owner allocation");
248 assert!(
249 offset <= usable_capacity,
250 "view pointer out of owner bounds"
251 );
252 let cap = usable_capacity - offset;
253 assert!(me.len <= cap, "view length out of owner bounds");
254
255 Ok(IoBufMut {
256 ptr: me.ptr,
257 len: me.len,
258 cap,
259 owner: me.owner,
260 })
261 }
262
263 pub fn into_mut_with_pool(self, pool: &BufferPool) -> IoBufMut {
269 match self.try_into_mut() {
270 Ok(buf) => buf,
271 Err(buf) => {
272 let mut result = pool.alloc(buf.len());
273 result.put_slice(buf.as_ref());
274 result
275 }
276 }
277 }
278}
279
280impl AsRef<[u8]> for IoBuf {
281 #[inline]
282 fn as_ref(&self) -> &[u8] {
283 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
286 }
287}
288
289impl Default for IoBuf {
290 fn default() -> Self {
291 Self {
292 ptr: NonNull::dangling(),
293 len: 0,
294 owner: OwnerRef::empty(),
295 }
296 }
297}
298
299impl PartialEq for IoBuf {
300 fn eq(&self, other: &Self) -> bool {
301 self.as_ref() == other.as_ref()
302 }
303}
304
305impl Eq for IoBuf {}
306
307impl PartialEq<[u8]> for IoBuf {
308 #[inline]
309 fn eq(&self, other: &[u8]) -> bool {
310 self.as_ref() == other
311 }
312}
313
314impl PartialEq<&[u8]> for IoBuf {
315 #[inline]
316 fn eq(&self, other: &&[u8]) -> bool {
317 self.as_ref() == *other
318 }
319}
320
321impl<const N: usize> PartialEq<[u8; N]> for IoBuf {
322 #[inline]
323 fn eq(&self, other: &[u8; N]) -> bool {
324 self.as_ref() == other
325 }
326}
327
328impl<const N: usize> PartialEq<&[u8; N]> for IoBuf {
329 #[inline]
330 fn eq(&self, other: &&[u8; N]) -> bool {
331 self.as_ref() == *other
332 }
333}
334
335impl Buf for IoBuf {
336 #[inline(always)]
337 fn remaining(&self) -> usize {
338 self.len
339 }
340
341 #[inline(always)]
342 fn chunk(&self) -> &[u8] {
343 self.as_ref()
344 }
345
346 #[inline(always)]
347 fn advance(&mut self, cnt: usize) {
348 if cnt > self.len {
349 panic_advance(cnt, self.len);
350 }
351 unsafe {
354 self.ptr = self.ptr.add(cnt);
355 }
356 self.len -= cnt;
357 }
358
359 #[inline]
360 fn copy_to_slice(&mut self, dst: &mut [u8]) {
361 if let Err(error) = self.try_copy_to_slice(dst) {
362 panic_try_get(error);
363 }
364 }
365
366 #[inline]
367 fn try_copy_to_slice(&mut self, dst: &mut [u8]) -> Result<(), TryGetError> {
368 if dst.len() > self.len {
369 return Err(TryGetError {
370 requested: dst.len(),
371 available: self.len,
372 });
373 }
374 unsafe {
378 std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), dst.as_mut_ptr(), dst.len());
379 self.ptr = self.ptr.add(dst.len());
380 }
381 self.len -= dst.len();
382 Ok(())
383 }
384
385 #[inline]
390 fn copy_to_bytes(&mut self, len: usize) -> Bytes {
391 assert!(len <= self.len, "copy_to_bytes out of bounds");
392 if len == 0 {
393 return Bytes::new();
394 }
395 if len == self.len {
396 return Bytes::from(std::mem::take(self));
397 }
398
399 if self.owner.is_external() {
403 let inner = unsafe { self.owner.external_bytes() };
407 let bytes = inner.slice_ref(&self.as_ref()[..len]);
408 self.advance(len);
409 return bytes;
410 }
411
412 let drained = Self {
413 ptr: self.ptr,
414 len,
415 owner: self.owner,
416 };
417 unsafe { drained.owner.clone_shared() };
419 self.advance(len);
420 Bytes::from(drained)
421 }
422}
423
424impl From<Vec<u8>> for IoBuf {
429 fn from(vec: Vec<u8>) -> Self {
430 let (ptr, len, owner) = OwnerRef::from_vec(vec);
431 Self { ptr, len, owner }
432 }
433}
434
435impl From<Bytes> for IoBuf {
442 fn from(bytes: Bytes) -> Self {
443 let (ptr, len, owner) = OwnerRef::from_bytes(bytes);
444 Self { ptr, len, owner }
445 }
446}
447
448impl From<BytesMut> for IoBuf {
450 fn from(bytes: BytesMut) -> Self {
451 Self::from(bytes.freeze())
452 }
453}
454
455impl<const N: usize> From<&'static [u8; N]> for IoBuf {
457 fn from(array: &'static [u8; N]) -> Self {
458 Self::from_static(array)
459 }
460}
461
462impl From<&'static [u8]> for IoBuf {
464 fn from(slice: &'static [u8]) -> Self {
465 Self::from_static(slice)
466 }
467}
468
469impl From<IoBuf> for Vec<u8> {
473 fn from(buf: IoBuf) -> Self {
474 buf.as_ref().to_vec()
475 }
476}
477
478impl From<IoBuf> for Bytes {
486 fn from(buf: IoBuf) -> Self {
487 if buf.is_empty() {
488 return Self::new();
489 }
490 if buf.owner.is_empty() {
491 let slice: &'static [u8] =
494 unsafe { std::slice::from_raw_parts(buf.ptr.as_ptr(), buf.len) };
495 return Self::from_static(slice);
496 }
497 if buf.owner.is_external() {
498 let inner = unsafe { buf.owner.external_bytes() };
502 return inner.slice_ref(buf.as_ref());
503 }
504 Self::from_owner(buf)
505 }
506}
507
508impl Write for IoBuf {
509 #[inline]
510 fn write(&self, buf: &mut impl BufMut) {
511 self.len().write(buf);
512 buf.put_slice(self.as_ref());
513 }
514
515 #[inline]
516 fn write_bufs(&self, buf: &mut impl BufsMut) {
517 self.len().write(buf);
518 buf.push(self.clone());
519 }
520}
521
522impl EncodeSize for IoBuf {
523 #[inline]
524 fn encode_size(&self) -> usize {
525 self.len().encode_size() + self.len()
526 }
527
528 #[inline]
529 fn encode_inline_size(&self) -> usize {
530 self.len().encode_size()
531 }
532}
533
534impl Read for IoBuf {
535 type Cfg = RangeCfg<usize>;
536
537 #[inline]
538 fn read_cfg(buf: &mut impl Buf, range: &Self::Cfg) -> Result<Self, Error> {
539 let len = usize::read_cfg(buf, range)?;
540 at_least(buf, len)?;
541 Ok(Self::from(buf.copy_to_bytes(len)))
542 }
543}
544
545#[cfg(feature = "arbitrary")]
546impl arbitrary::Arbitrary<'_> for IoBuf {
547 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
548 let len = u.arbitrary_len::<u8>()?;
549 let data: Vec<u8> = u.arbitrary_iter()?.take(len).collect::<Result<_, _>>()?;
550 Ok(Self::from(data))
551 }
552}
553
554pub struct IoBufMut {
583 ptr: NonNull<u8>,
584 len: usize,
585 cap: usize,
586 owner: OwnerRef,
587}
588
589unsafe impl Send for IoBufMut {}
592unsafe impl Sync for IoBufMut {}
595
596impl std::fmt::Debug for IoBufMut {
599 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
600 f.debug_struct("IoBufMut")
601 .field("len", &self.len)
602 .field("cap", &self.cap)
603 .field("pooled", &self.is_pooled())
604 .finish()
605 }
606}
607
608impl Drop for IoBufMut {
609 #[inline]
610 fn drop(&mut self) {
611 unsafe { self.owner.release_unique_mut_at(self.ptr, self.cap) };
613 }
614}
615
616impl Default for IoBufMut {
617 fn default() -> Self {
618 Self {
619 ptr: NonNull::dangling(),
620 len: 0,
621 cap: 0,
622 owner: OwnerRef::empty(),
623 }
624 }
625}
626
627impl IoBufMut {
628 #[inline]
633 pub fn with_capacity(capacity: usize) -> Self {
634 Self::with_alignment(capacity, NonZeroUsize::MIN)
635 }
636
637 #[inline]
651 pub fn with_alignment(capacity: usize, alignment: NonZeroUsize) -> Self {
652 if capacity == 0 {
653 return Self::default();
654 }
655 let (ptr, cap, owner) = HeapOwner::allocate_aligned_mut(capacity, alignment.get(), false);
656 Self {
657 ptr,
658 len: 0,
659 cap,
660 owner,
661 }
662 }
663
664 #[inline]
676 pub fn zeroed_with_alignment(len: usize, alignment: NonZeroUsize) -> Self {
677 if len == 0 {
678 return Self::default();
679 }
680 let (ptr, cap, owner) = HeapOwner::allocate_aligned_mut(len, alignment.get(), true);
681 Self {
682 ptr,
683 len,
684 cap,
685 owner,
686 }
687 }
688
689 #[inline]
695 pub fn zeroed(len: usize) -> Self {
696 Self::zeroed_with_alignment(len, NonZeroUsize::MIN)
697 }
698
699 #[inline]
705 pub(crate) unsafe fn from_pooled_parts(buffer: PooledBuffer) -> Self {
706 let cap = buffer.capacity();
707 let ptr = buffer.data_ptr();
708 let owner = unsafe { buffer.owner_ref() };
710 Self {
711 ptr,
712 len: 0,
713 cap,
714 owner,
715 }
716 }
717
718 #[inline]
720 pub fn is_pooled(&self) -> bool {
721 self.owner.is_pooled()
722 }
723
724 #[inline]
735 pub unsafe fn set_len(&mut self, len: usize) {
736 assert!(
737 len <= self.capacity(),
738 "set_len({len}) exceeds capacity({})",
739 self.capacity()
740 );
741 self.len = len;
742 }
743
744 #[inline]
746 pub const fn len(&self) -> usize {
747 self.len
748 }
749
750 #[inline]
752 pub const fn is_empty(&self) -> bool {
753 self.len == 0
754 }
755
756 #[inline]
764 pub fn freeze(self) -> IoBuf {
765 let mut me = ManuallyDrop::new(self);
766 if me.len == 0 {
767 unsafe { me.owner.release_unique_mut_at(me.ptr, me.cap) };
770 return IoBuf::default();
771 }
772 let ptr = me.ptr;
773 let cap = me.cap;
774 unsafe { me.owner.ensure_heap_header_for_mut(ptr, cap) };
778 IoBuf {
779 ptr: me.ptr,
780 len: me.len,
781 owner: me.owner,
782 }
783 }
784
785 #[inline]
787 pub const fn capacity(&self) -> usize {
788 self.cap
789 }
790
791 #[inline]
793 pub const fn as_mut_ptr(&mut self) -> *mut u8 {
794 self.ptr.as_ptr()
795 }
796
797 #[inline]
801 pub fn truncate(&mut self, len: usize) {
802 self.len = self.len.min(len);
803 }
804
805 #[inline]
807 pub const fn clear(&mut self) {
808 self.len = 0;
809 }
810}
811
812impl AsRef<[u8]> for IoBufMut {
813 #[inline]
814 fn as_ref(&self) -> &[u8] {
815 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
817 }
818}
819
820impl AsMut<[u8]> for IoBufMut {
821 #[inline]
822 fn as_mut(&mut self) -> &mut [u8] {
823 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
826 }
827}
828
829impl PartialEq<[u8]> for IoBufMut {
830 #[inline]
831 fn eq(&self, other: &[u8]) -> bool {
832 self.as_ref() == other
833 }
834}
835
836impl PartialEq<&[u8]> for IoBufMut {
837 #[inline]
838 fn eq(&self, other: &&[u8]) -> bool {
839 self.as_ref() == *other
840 }
841}
842
843impl<const N: usize> PartialEq<[u8; N]> for IoBufMut {
844 #[inline]
845 fn eq(&self, other: &[u8; N]) -> bool {
846 self.as_ref() == other
847 }
848}
849
850impl<const N: usize> PartialEq<&[u8; N]> for IoBufMut {
851 #[inline]
852 fn eq(&self, other: &&[u8; N]) -> bool {
853 self.as_ref() == *other
854 }
855}
856
857impl Buf for IoBufMut {
858 #[inline(always)]
859 fn remaining(&self) -> usize {
860 self.len
861 }
862
863 #[inline(always)]
864 fn chunk(&self) -> &[u8] {
865 self.as_ref()
866 }
867
868 #[inline(always)]
869 fn advance(&mut self, cnt: usize) {
870 if cnt > self.len {
871 panic_advance(cnt, self.len);
872 }
873 unsafe {
877 self.ptr = self.ptr.add(cnt);
878 }
879 self.len -= cnt;
880 self.cap -= cnt;
881 }
882
883 #[inline]
884 fn copy_to_slice(&mut self, dst: &mut [u8]) {
885 if let Err(error) = self.try_copy_to_slice(dst) {
886 panic_try_get(error);
887 }
888 }
889
890 #[inline]
891 fn try_copy_to_slice(&mut self, dst: &mut [u8]) -> Result<(), TryGetError> {
892 if dst.len() > self.len {
893 return Err(TryGetError {
894 requested: dst.len(),
895 available: self.len,
896 });
897 }
898 unsafe {
903 std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), dst.as_mut_ptr(), dst.len());
904 self.ptr = self.ptr.add(dst.len());
905 }
906 self.len -= dst.len();
907 self.cap -= dst.len();
908 Ok(())
909 }
910
911 #[inline]
918 fn copy_to_bytes(&mut self, len: usize) -> Bytes {
919 assert!(len <= self.len, "copy_to_bytes out of bounds");
920 if len == 0 {
921 return Bytes::new();
922 }
923 if len == self.len {
924 let drained = std::mem::take(self);
925 return Bytes::from(drained.freeze());
926 }
927
928 let bytes = Bytes::copy_from_slice(&self.as_ref()[..len]);
929 self.advance(len);
930 bytes
931 }
932}
933
934unsafe impl BufMut for IoBufMut {
937 #[inline(always)]
938 fn remaining_mut(&self) -> usize {
939 self.cap - self.len
940 }
941
942 #[inline(always)]
943 unsafe fn advance_mut(&mut self, cnt: usize) {
944 let writable = self.cap - self.len;
945 if cnt > writable {
946 panic_advance(cnt, writable);
947 }
948 self.len += cnt;
949 }
950
951 #[inline(always)]
952 fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
953 unsafe {
956 let ptr = self.ptr.as_ptr().add(self.len);
957 bytes::buf::UninitSlice::from_raw_parts_mut(ptr, self.cap - self.len)
958 }
959 }
960
961 #[inline]
962 fn put_slice(&mut self, src: &[u8]) {
963 let writable = self.cap - self.len;
964 if src.len() > writable {
965 panic_advance(src.len(), writable);
966 }
967 unsafe {
969 std::ptr::copy_nonoverlapping(src.as_ptr(), self.ptr.as_ptr().add(self.len), src.len());
970 }
971 self.len += src.len();
972 }
973
974 #[inline]
975 fn put_bytes(&mut self, val: u8, cnt: usize) {
976 let writable = self.cap - self.len;
977 if cnt > writable {
978 panic_advance(cnt, writable);
979 }
980 unsafe {
982 std::ptr::write_bytes(self.ptr.as_ptr().add(self.len), val, cnt);
983 }
984 self.len += cnt;
985 }
986
987 #[inline]
988 fn put<T: Buf>(&mut self, mut src: T)
989 where
990 Self: Sized,
991 {
992 let remaining = src.remaining();
994 if remaining > self.cap - self.len {
995 panic_advance(remaining, self.cap - self.len);
996 }
997 while src.has_remaining() {
998 let chunk = src.chunk();
999 let cnt = chunk.len();
1000 let writable = self.cap - self.len;
1004 if cnt > writable {
1005 panic_advance(cnt, writable);
1006 }
1007 unsafe {
1009 std::ptr::copy_nonoverlapping(chunk.as_ptr(), self.ptr.as_ptr().add(self.len), cnt);
1010 }
1011 self.len += cnt;
1012 src.advance(cnt);
1013 }
1014 }
1015}
1016
1017impl From<&[u8]> for IoBufMut {
1019 fn from(slice: &[u8]) -> Self {
1020 let mut buf = Self::with_capacity(slice.len());
1021 buf.put_slice(slice);
1022 buf
1023 }
1024}
1025
1026impl<const N: usize> From<[u8; N]> for IoBufMut {
1028 fn from(array: [u8; N]) -> Self {
1029 Self::from(array.as_ref())
1030 }
1031}
1032
1033impl<const N: usize> From<&[u8; N]> for IoBufMut {
1035 fn from(array: &[u8; N]) -> Self {
1036 Self::from(array.as_ref())
1037 }
1038}
1039
1040impl From<Vec<u8>> for IoBufMut {
1047 fn from(vec: Vec<u8>) -> Self {
1048 let mut buf = Self::with_capacity(vec.capacity());
1049 buf.put_slice(&vec);
1050 buf
1051 }
1052}
1053
1054impl From<BytesMut> for IoBufMut {
1060 fn from(bytes: BytesMut) -> Self {
1061 let mut out = Self::with_capacity(bytes.capacity());
1062 out.put_slice(bytes.as_ref());
1063 out
1064 }
1065}
1066
1067impl From<Bytes> for IoBufMut {
1072 fn from(bytes: Bytes) -> Self {
1073 Self::from(bytes.as_ref())
1074 }
1075}
1076
1077impl From<IoBuf> for IoBufMut {
1080 fn from(buf: IoBuf) -> Self {
1081 match buf.try_into_mut() {
1082 Ok(buf) => buf,
1083 Err(buf) => Self::from(buf.as_ref()),
1084 }
1085 }
1086}
1087
1088#[cold]
1091#[inline(never)]
1092fn panic_try_get(error: TryGetError) -> ! {
1093 panic!("{error}");
1094}
1095
1096fn resolve_range(len: usize, range: impl RangeBounds<usize>) -> (usize, usize) {
1101 let start = match range.start_bound() {
1102 Bound::Included(&n) => n,
1103 Bound::Excluded(&n) => n.checked_add(1).expect("range start overflow"),
1104 Bound::Unbounded => 0,
1105 };
1106 let end = match range.end_bound() {
1107 Bound::Included(&n) => n.checked_add(1).expect("range end overflow"),
1108 Bound::Excluded(&n) => n,
1109 Bound::Unbounded => len,
1110 };
1111 assert!(start <= end, "slice start must be <= end");
1112 assert!(end <= len, "slice out of bounds");
1113 (start, end)
1114}
1115
1116#[cfg(all(test, not(feature = "loom")))]
1117mod tests {
1118 use super::{
1119 super::{bufs::IoBufs, pool::BufferPoolConfig},
1120 *,
1121 };
1122 use bytes::{Bytes, BytesMut};
1123 use commonware_codec::{Decode, Encode, RangeCfg};
1124 use core::ops::Bound;
1125 use std::mem::size_of;
1126
1127 fn test_pool() -> BufferPool {
1128 cfg_if::cfg_if! {
1129 if #[cfg(miri)] {
1130 let pool_config = BufferPoolConfig::for_network()
1132 .with_pool_min_size(0)
1133 .with_max_per_class(commonware_utils::NZU32!(32));
1134 } else {
1135 let pool_config = BufferPoolConfig::for_network().with_pool_min_size(0);
1136 }
1137 }
1138 let mut registry = crate::telemetry::metrics::Registry::default();
1139 BufferPool::new(pool_config, &mut registry)
1140 }
1141
1142 #[test]
1143 fn test_iobuf_core_behaviors() {
1144 let buf1 = IoBuf::from(vec![1u8; 1000]);
1146 let buf2 = buf1.clone();
1147 assert_eq!(buf1.as_ref().as_ptr(), buf2.as_ref().as_ptr());
1148
1149 let data = vec![1u8, 2, 3, 4, 5];
1151 let copied = IoBuf::copy_from_slice(&data);
1152 assert_eq!(copied, [1, 2, 3, 4, 5]);
1153 assert_eq!(copied.len(), 5);
1154 let empty = IoBuf::copy_from_slice(&[]);
1155 assert!(empty.is_empty());
1156
1157 let eq = IoBuf::from(b"hello");
1159 assert_eq!(eq, *b"hello");
1160 assert_eq!(eq, b"hello");
1161 assert_ne!(eq, *b"world");
1162 assert_ne!(eq, b"world");
1163 assert_eq!(IoBuf::from(b"hello"), IoBuf::from(b"hello"));
1164 assert_ne!(IoBuf::from(b"hello"), IoBuf::from(b"world"));
1165 let bytes: Bytes = IoBuf::from(b"bytes").into();
1166 assert_eq!(bytes.as_ref(), b"bytes");
1167
1168 let mut buf = IoBuf::from(b"hello world");
1170 assert_eq!(buf.len(), buf.remaining());
1171 assert_eq!(buf.as_ref(), buf.chunk());
1172 assert_eq!(buf.remaining(), 11);
1173 buf.advance(6);
1174 assert_eq!(buf.chunk(), b"world");
1175 assert_eq!(buf.len(), buf.remaining());
1176
1177 let first = buf.copy_to_bytes(2);
1179 assert_eq!(&first[..], b"wo");
1180 let rest = buf.copy_to_bytes(3);
1181 assert_eq!(&rest[..], b"rld");
1182 assert_eq!(buf.remaining(), 0);
1183
1184 let src = IoBuf::from(b"hello world");
1186 assert_eq!(src.slice(..5), b"hello");
1187 assert_eq!(src.slice(6..), b"world");
1188 assert_eq!(src.slice(3..8), b"lo wo");
1189 assert!(src.slice(5..5).is_empty());
1190 }
1191
1192 #[test]
1193 fn test_iobuf_from_conversions_are_zero_copy() {
1194 let mut vec = Vec::with_capacity(128);
1199 vec.extend_from_slice(b"adopt");
1200 let ptr = vec.as_ptr();
1201 let buf = IoBuf::from(vec);
1202 assert_eq!(buf.as_ref().as_ptr(), ptr);
1203
1204 let vec = b"exact".to_vec();
1206 let ptr = vec.as_ptr();
1207 let buf = IoBuf::from(vec);
1208 assert_eq!(buf.as_ref().as_ptr(), ptr);
1209
1210 let bytes = Bytes::from(b"bytes".to_vec());
1212 let ptr = bytes.as_ptr();
1213 let buf = IoBuf::from(bytes);
1214 assert_eq!(buf.as_ref().as_ptr(), ptr);
1215
1216 let mut bytes = BytesMut::with_capacity(16);
1218 bytes.put_slice(b"frozen");
1219 let ptr = bytes.as_ref().as_ptr();
1220 let buf = IoBuf::from(bytes);
1221 assert_eq!(buf.as_ref().as_ptr(), ptr);
1222
1223 static DATA: [u8; 4] = *b"data";
1225 let buf = IoBuf::from(&DATA[..]);
1226 assert_eq!(buf.as_ref().as_ptr(), DATA.as_ptr());
1227 }
1228
1229 #[test]
1230 fn test_iobuf_codec_roundtrip() {
1231 let cfg: RangeCfg<usize> = (0..=1024).into();
1232
1233 let original = IoBuf::from(b"hello world");
1234 let encoded = original.encode();
1235 let decoded = IoBuf::decode_cfg(encoded, &cfg).unwrap();
1236 assert_eq!(original, decoded);
1237
1238 let empty = IoBuf::default();
1239 let encoded = empty.encode();
1240 let decoded = IoBuf::decode_cfg(encoded, &cfg).unwrap();
1241 assert_eq!(empty, decoded);
1242
1243 let large_cfg: RangeCfg<usize> = (0..=20000).into();
1244 let large = IoBuf::from(vec![42u8; 10000]);
1245 let encoded = large.encode();
1246 let decoded = IoBuf::decode_cfg(encoded, &large_cfg).unwrap();
1247 assert_eq!(large, decoded);
1248
1249 let mut truncated = BytesMut::new();
1250 4usize.write(&mut truncated);
1251 truncated.extend_from_slice(b"xy");
1252 let mut truncated = truncated.freeze();
1253 assert!(IoBuf::read_cfg(&mut truncated, &cfg).is_err());
1254
1255 let mut direct = BytesMut::new();
1257 4usize.write(&mut direct);
1258 direct.extend_from_slice(b"wxyz");
1259 let mut direct = direct.freeze();
1260 let decoded = IoBuf::read_cfg(&mut direct, &cfg).unwrap();
1261 assert_eq!(decoded, b"wxyz");
1262 }
1263
1264 #[test]
1265 #[should_panic(expected = "cannot advance")]
1266 fn test_iobuf_advance_past_end() {
1267 let mut buf = IoBuf::from(b"hello");
1268 buf.advance(10);
1269 }
1270
1271 #[test]
1272 fn test_iobuf_copy_to_slice_paths() {
1273 let mut buf = IoBuf::from(b"hello world");
1274 let mut dst = [0u8; 5];
1275 buf.copy_to_slice(&mut dst);
1276 assert_eq!(&dst, b"hello");
1277 assert_eq!(buf.as_ref(), b" world");
1278
1279 let mut dst = [0u8; 3];
1280 buf.try_copy_to_slice(&mut dst).unwrap();
1281 assert_eq!(&dst, b" wo");
1282
1283 let mut dst = [0u8; 4];
1285 let err = buf.try_copy_to_slice(&mut dst).unwrap_err();
1286 assert_eq!(err.requested, 4);
1287 assert_eq!(err.available, 3);
1288 assert_eq!(buf.as_ref(), b"rld");
1289 }
1290
1291 #[test]
1292 #[should_panic(expected = "Not enough bytes remaining in buffer")]
1293 fn test_iobuf_copy_to_slice_past_end() {
1294 let mut buf = IoBuf::from(b"ab");
1295 let mut dst = [0u8; 3];
1296 buf.copy_to_slice(&mut dst);
1297 }
1298
1299 #[test]
1300 #[should_panic(expected = "copy_to_bytes out of bounds")]
1301 fn test_iobuf_copy_to_bytes_past_end() {
1302 let mut buf = IoBuf::from(b"ab");
1303 let _ = buf.copy_to_bytes(3);
1304 }
1305
1306 #[test]
1307 fn test_iobuf_slice_excluded_start_bound() {
1308 let buf = IoBuf::from(b"hello");
1310 let sliced = buf.slice((Bound::Excluded(0), Bound::Unbounded));
1311 assert_eq!(sliced, b"ello");
1312 }
1313
1314 #[test]
1315 #[should_panic(expected = "slice out of bounds")]
1316 fn test_iobuf_slice_out_of_bounds() {
1317 let buf = IoBuf::from(b"hello");
1318 let _ = buf.slice(..6);
1319 }
1320
1321 #[test]
1322 #[should_panic(expected = "slice start must be <= end")]
1323 fn test_iobuf_slice_inverted_range() {
1324 let buf = IoBuf::from(b"hello");
1325 #[allow(clippy::reversed_empty_ranges)]
1326 let _ = buf.slice(3..1);
1327 }
1328
1329 #[test]
1330 #[should_panic(expected = "range end overflow")]
1331 fn test_iobuf_slice_inclusive_end_overflow() {
1332 let buf = IoBuf::from(b"hello");
1333 let _ = buf.slice(0..=usize::MAX);
1334 }
1335
1336 #[test]
1337 #[should_panic(expected = "range start overflow")]
1338 fn test_iobuf_slice_excluded_start_overflow() {
1339 let buf = IoBuf::from(b"hello");
1340 let _ = buf.slice((Bound::Excluded(usize::MAX), Bound::Unbounded));
1341 }
1342
1343 #[test]
1344 fn test_iobuf_try_into_mut_empty_and_static() {
1345 let buf = IoBuf::default().try_into_mut().expect("empty converts");
1347 assert!(buf.is_empty());
1348 assert_eq!(buf.capacity(), 0);
1349
1350 let err = IoBuf::from(b"static").try_into_mut().unwrap_err();
1352 assert_eq!(err, b"static");
1353
1354 let empty = Bytes::from(IoBuf::default());
1356 assert!(empty.is_empty());
1357
1358 let empty = IoBuf::from(&b""[..]);
1360 assert!(empty.is_empty());
1361 assert!(empty.try_into_mut().is_ok());
1362 }
1363
1364 #[test]
1365 fn test_iobuf_split_to_consistent_across_backings() {
1366 let pool = test_pool();
1368 let mut pooled = pool.try_alloc(256).expect("pooled allocation");
1369 pooled.put_slice(b"hello world");
1370 let mut pooled_buf = pooled.freeze();
1371 let mut bytes_buf = IoBuf::from(b"hello world");
1372
1373 assert!(pooled_buf.is_pooled());
1374 assert!(!bytes_buf.is_pooled());
1375
1376 let pooled_empty = pooled_buf.split_to(0);
1377 let bytes_empty = bytes_buf.split_to(0);
1378 assert_eq!(pooled_empty, bytes_empty);
1379 assert_eq!(pooled_buf, bytes_buf);
1380 assert!(!pooled_empty.is_pooled());
1381
1382 let pooled_prefix = pooled_buf.split_to(5);
1383 let bytes_prefix = bytes_buf.split_to(5);
1384 assert_eq!(pooled_prefix, bytes_prefix);
1385 assert_eq!(pooled_buf, bytes_buf);
1386 assert!(pooled_prefix.is_pooled());
1387
1388 let pooled_rest = pooled_buf.split_to(pooled_buf.len());
1389 let bytes_rest = bytes_buf.split_to(bytes_buf.len());
1390 assert_eq!(pooled_rest, bytes_rest);
1391 assert_eq!(pooled_buf, bytes_buf);
1392 assert!(pooled_buf.is_empty());
1393 assert!(bytes_buf.is_empty());
1394 assert!(!pooled_buf.is_pooled());
1395 }
1396
1397 #[test]
1398 #[should_panic(expected = "split_to out of bounds")]
1399 fn test_iobuf_split_to_out_of_bounds() {
1400 let mut buf = IoBuf::from(b"abc");
1401 let _ = buf.split_to(4);
1402 }
1403
1404 #[test]
1405 fn test_iobufmut_core_behaviors() {
1406 let mut buf = IoBufMut::with_capacity(100);
1408 assert!(buf.capacity() >= 100);
1409 assert_eq!(buf.len(), 0);
1410 buf.put_slice(b"hello");
1411 buf.put_slice(b" world");
1412 assert_eq!(buf, b"hello world");
1413 assert_eq!(buf, &b"hello world"[..]);
1414 assert_eq!(buf.freeze(), b"hello world");
1415
1416 let mut zeroed = IoBufMut::zeroed(10);
1418 assert_eq!(zeroed, &[0u8; 10]);
1419 unsafe { zeroed.set_len(5) };
1421 assert_eq!(zeroed, &[0u8; 5]);
1422 zeroed.as_mut()[..5].copy_from_slice(b"hello");
1423 assert_eq!(&zeroed.as_ref()[..5], b"hello");
1424 let frozen = zeroed.freeze();
1425 let vec: Vec<u8> = frozen.into();
1426 assert_eq!(&vec[..5], b"hello");
1427
1428 let pool = test_pool();
1430 let mut pooled = pool.alloc(8);
1431 assert!(pooled.is_empty());
1432 pooled.put_slice(b"x");
1433 assert!(!pooled.is_empty());
1434 }
1435
1436 #[test]
1437 fn test_iobufmut_low_alignment_freeze_after_advance_recovers_capacity() {
1438 let mut buf = IoBufMut::with_capacity(16);
1439 assert_eq!(buf.capacity(), 16);
1440 buf.put_slice(b"abcdefghijklmnop");
1441 buf.advance(3);
1442 assert_eq!(buf.as_ref(), b"defghijklmnop");
1443 assert_eq!(buf.capacity(), 13);
1444
1445 let frozen = buf.freeze();
1446 assert_eq!(frozen.as_ref(), b"defghijklmnop");
1447
1448 let recovered = frozen
1449 .try_into_mut()
1450 .expect("unique low-alignment buffer should recover mutability");
1451 assert_eq!(recovered.as_ref(), b"defghijklmnop");
1452 assert_eq!(recovered.capacity(), 13);
1453 }
1454
1455 #[test]
1456 fn test_iobufmut_buf_trait() {
1457 let mut buf = IoBufMut::from(b"hello world");
1459 assert_eq!(buf.remaining(), 11);
1460 assert_eq!(buf.chunk(), b"hello world");
1461
1462 buf.advance(6);
1463 assert_eq!(buf.remaining(), 5);
1464 assert_eq!(buf.chunk(), b"world");
1465
1466 buf.advance(5);
1467 assert_eq!(buf.remaining(), 0);
1468 assert!(buf.chunk().is_empty());
1469 }
1470
1471 #[test]
1472 #[should_panic(expected = "cannot advance")]
1473 fn test_iobufmut_advance_past_end() {
1474 let mut buf = IoBufMut::from(b"hello");
1475 buf.advance(10);
1476 }
1477
1478 #[test]
1479 fn test_iobufmut_copy_to_slice_tracks_len_and_cap() {
1480 let mut buf = IoBufMut::with_capacity(16);
1484 buf.put_slice(b"abcdefgh");
1485
1486 let mut dst = [0u8; 3];
1487 buf.copy_to_slice(&mut dst);
1488 assert_eq!(&dst, b"abc");
1489 assert_eq!(buf.as_ref(), b"defgh");
1490 assert_eq!(buf.len(), 5);
1491 assert_eq!(buf.capacity(), 13);
1492
1493 let mut dst = [0u8; 2];
1495 buf.try_copy_to_slice(&mut dst).unwrap();
1496 assert_eq!(&dst, b"de");
1497 assert_eq!(buf.capacity(), 11);
1498
1499 let mut dst = [0u8; 4];
1501 let err = buf.try_copy_to_slice(&mut dst).unwrap_err();
1502 assert_eq!(err.requested, 4);
1503 assert_eq!(err.available, 3);
1504 assert_eq!(buf.as_ref(), b"fgh");
1505 assert_eq!(buf.capacity(), 11);
1506
1507 let frozen = buf.freeze();
1512 assert_eq!(frozen.as_ref(), b"fgh");
1513 let recovered = frozen.try_into_mut().expect("unique buffer recovers");
1514 assert_eq!(recovered.as_ref(), b"fgh");
1515 assert_eq!(recovered.capacity(), 11);
1516 }
1517
1518 #[test]
1519 fn test_iobufmut_write_after_partial_advance_appends_at_tail() {
1520 let mut buf = IoBufMut::with_capacity(16);
1524 buf.put_slice(b"hello");
1525 buf.advance(2);
1526 buf.put_slice(b"world");
1527 assert_eq!(buf.as_ref(), b"lloworld");
1528 assert_eq!(buf.len(), 8);
1529 assert_eq!(buf.capacity(), 14);
1530
1531 let pool = test_pool();
1534 let mut buf = pool.alloc(16);
1535 let capacity = buf.capacity();
1536 buf.put_slice(b"hello");
1537 buf.advance(2);
1538 buf.put_slice(b"world");
1539 assert_eq!(buf.as_ref(), b"lloworld");
1540 assert_eq!(buf.len(), 8);
1541 assert_eq!(buf.capacity(), capacity - 2);
1542 }
1543
1544 #[test]
1545 #[should_panic(expected = "Not enough bytes remaining in buffer")]
1546 fn test_iobufmut_copy_to_slice_past_end() {
1547 let mut buf = IoBufMut::from(b"ab");
1548 let mut dst = [0u8; 3];
1549 buf.copy_to_slice(&mut dst);
1550 }
1551
1552 #[test]
1553 #[should_panic(expected = "copy_to_bytes out of bounds")]
1554 fn test_iobufmut_copy_to_bytes_past_end() {
1555 let mut buf = IoBufMut::from(b"ab");
1556 let _ = buf.copy_to_bytes(3);
1557 }
1558
1559 #[test]
1560 fn test_iobufmut_put_bytes_success() {
1561 let mut buf = IoBufMut::with_capacity(8);
1562 buf.put_bytes(7, 5);
1563 assert_eq!(buf.as_ref(), &[7u8; 5]);
1564 assert_eq!(buf.len(), 5);
1565 assert_eq!(buf.remaining_mut(), 3);
1566 }
1567
1568 #[test]
1569 fn test_iobufmut_put_multi_chunk_source() {
1570 let mut buf = IoBufMut::with_capacity(8);
1571 buf.put((&b"hel"[..]).chain(&b"lo"[..]));
1572 assert_eq!(buf.as_ref(), b"hello");
1573 assert_eq!(buf.remaining_mut(), 3);
1574 }
1575
1576 #[test]
1577 #[should_panic(expected = "cannot advance past end of buffer")]
1578 fn test_iobufmut_put_slice_past_capacity() {
1579 let mut buf = IoBufMut::with_capacity(4);
1580 buf.put_slice(b"hello");
1581 }
1582
1583 #[test]
1584 #[should_panic(expected = "cannot advance past end of buffer")]
1585 fn test_iobufmut_put_bytes_past_capacity() {
1586 let mut buf = IoBufMut::with_capacity(4);
1587 buf.put_bytes(0, 5);
1588 }
1589
1590 #[test]
1591 #[should_panic(expected = "cannot advance past end of buffer")]
1592 fn test_iobufmut_advance_mut_past_capacity() {
1593 let mut buf = IoBufMut::with_capacity(4);
1594 unsafe { buf.advance_mut(5) };
1597 }
1598
1599 #[test]
1600 #[should_panic(expected = "cannot advance past end of buffer")]
1601 fn test_iobufmut_put_past_capacity() {
1602 let mut buf = IoBufMut::with_capacity(4);
1603 buf.put(&b"hello"[..]);
1604 }
1605
1606 #[test]
1607 fn test_iobuf_additional_conversion_and_trait_paths() {
1608 let pool = test_pool();
1609
1610 let mut pooled_mut = pool.alloc(4);
1611 pooled_mut.put_slice(b"data");
1612 let pooled = pooled_mut.freeze();
1613 assert!(!pooled.as_ptr().is_null());
1614
1615 let mut adopted_vec = Vec::with_capacity(64);
1618 adopted_vec.extend_from_slice(&[1u8, 2, 3]);
1619 let unique = IoBuf::from(adopted_vec);
1620 let unique_mut = unique.try_into_mut().expect("adopted vec should convert");
1621 assert_eq!(unique_mut.as_ref(), &[1u8, 2, 3]);
1622
1623 let shared = IoBuf::from(vec![4u8, 5, 6]);
1624 let _shared_clone = shared.clone();
1625 assert!(shared.try_into_mut().is_err());
1626
1627 let external = IoBuf::from(vec![7u8, 8, 9]);
1630 assert!(external.try_into_mut().is_err());
1631
1632 let expected: &[u8] = &[9u8, 8];
1633 let eq_buf = IoBuf::from(vec![9u8, 8]);
1634 assert!(PartialEq::<[u8]>::eq(&eq_buf, expected));
1635
1636 let static_slice: &'static [u8] = b"static";
1637 assert_eq!(IoBuf::from(static_slice), b"static");
1638
1639 let mut pooled_mut = pool.alloc(3);
1640 pooled_mut.put_slice(b"xyz");
1641 let pooled = pooled_mut.freeze();
1642 let vec_out: Vec<u8> = pooled.clone().into();
1643 let bytes_out: Bytes = pooled.into();
1644 assert_eq!(vec_out, b"xyz");
1645 assert_eq!(bytes_out.as_ref(), b"xyz");
1646 }
1647
1648 #[test]
1649 fn test_iobuf_from_bytes_zero_copy_round_trip() {
1650 let bytes = Bytes::from(vec![1u8; 64]);
1652 let payload_ptr = bytes.as_ptr();
1653 let buf = IoBuf::from(bytes.clone());
1654 assert_eq!(buf.as_ptr(), payload_ptr);
1655 assert_eq!(buf, bytes.as_ref());
1656
1657 let out: Bytes = buf.into();
1660 assert_eq!(out.as_ptr(), payload_ptr);
1661 assert_eq!(out, bytes);
1662
1663 let sliced = IoBuf::from(bytes).slice(8..32);
1665 let sliced_ptr = sliced.as_ptr();
1666 let sliced_out: Bytes = sliced.into();
1667 assert_eq!(sliced_out.as_ptr(), sliced_ptr);
1668 assert_eq!(sliced_out.len(), 24);
1669 }
1670
1671 #[test]
1672 fn test_iobuf_from_bytes_mut_zero_copy() {
1673 let mut bytes = BytesMut::with_capacity(32);
1674 bytes.extend_from_slice(b"hello");
1675 let payload_ptr = bytes.as_ref().as_ptr();
1676 let buf = IoBuf::from(bytes);
1677 assert_eq!(buf.as_ptr(), payload_ptr);
1678 assert_eq!(buf, b"hello");
1679 }
1680
1681 #[test]
1682 fn test_iobuf_static_into_bytes_uses_from_static() {
1683 let buf = IoBuf::from(b"static-payload");
1684 let payload_ptr = buf.as_ptr();
1685 let bytes: Bytes = buf.into();
1686 assert_eq!(bytes.as_ptr(), payload_ptr);
1687 assert_eq!(bytes.as_ref(), b"static-payload");
1688 }
1689
1690 #[test]
1691 fn test_iobuf_vec_adoption_round_trip_zero_copy() {
1692 let mut vec = Vec::with_capacity(128);
1695 vec.extend_from_slice(b"adopted payload");
1696 let base = vec.as_ptr() as usize;
1697 let buf = IoBuf::from(vec);
1698 assert_eq!(buf.as_ptr() as usize, base);
1699
1700 let mut recovered = buf
1701 .try_into_mut()
1702 .expect("adopted vec recovers mutability zero-copy");
1703 assert_eq!(recovered.as_mut_ptr() as usize, base);
1704 assert_eq!(recovered.as_ref(), b"adopted payload");
1705 assert!(recovered.capacity() > recovered.len());
1706 recovered.put_slice(b"!");
1707 assert_eq!(recovered.as_ref(), b"adopted payload!");
1708 }
1709
1710 #[test]
1711 fn test_iobuf_read_cfg_zero_copy_from_iobuf_source() {
1712 let cfg: RangeCfg<usize> = (0..=1024).into();
1715 let mut source = IoBuf::from(IoBuf::from(vec![7u8; 100]).encode());
1716 let prefix = source.len() - 100;
1717 let payload_ptr = source.as_ref()[prefix..].as_ptr();
1718 let decoded = IoBuf::read_cfg(&mut source, &cfg).unwrap();
1719 assert_eq!(decoded.len(), 100);
1720 assert_eq!(decoded.as_ptr(), payload_ptr);
1721 assert_eq!(decoded, [7u8; 100]);
1722 }
1723
1724 #[test]
1725 #[should_panic(expected = "cannot advance")]
1726 fn test_iobufmut_put_does_not_trust_lying_buf() {
1727 struct LyingBuf;
1731 impl Buf for LyingBuf {
1732 fn remaining(&self) -> usize {
1733 1
1734 }
1735 fn chunk(&self) -> &[u8] {
1736 &[0xAB; 64]
1737 }
1738 fn advance(&mut self, _cnt: usize) {}
1739 }
1740
1741 let mut buf = IoBufMut::with_capacity(8);
1742 buf.put(LyingBuf);
1743 }
1744
1745 #[test]
1746 #[cfg(target_pointer_width = "64")]
1747 fn test_iobuf_handle_sizes() {
1748 assert_eq!(size_of::<IoBuf>(), 24);
1749 assert_eq!(size_of::<IoBufMut>(), 32);
1750 }
1751
1752 #[test]
1753 fn test_iobuf_into_mut_with_pool() {
1754 let pool = test_pool();
1755
1756 let mut unique = pool.alloc(4);
1758 unique.put_slice(b"data");
1759 let unique_ptr = unique.as_mut_ptr();
1760 let mut recovered = unique.freeze().into_mut_with_pool(&pool);
1761 assert_eq!(recovered.as_ref(), b"data");
1762 assert_eq!(recovered.as_mut_ptr(), unique_ptr);
1763
1764 let mut shared = pool.alloc(4);
1766 shared.put_slice(b"copy");
1767 let shared = shared.freeze();
1768 let shared_ptr = shared.as_ptr();
1769 let _clone = shared.clone();
1770 let mut copied = shared.into_mut_with_pool(&pool);
1771 assert_eq!(copied.as_ref(), b"copy");
1772 assert_ne!(copied.as_mut_ptr() as *const u8, shared_ptr);
1773 assert!(copied.is_pooled());
1774
1775 let mut mirror = pool.alloc(8);
1778 mirror.put_slice(b"abcdefgh");
1779 let mirror_cap = mirror.capacity();
1780 let mirror_ptr = mirror.as_mut_ptr();
1781 let frozen = mirror.freeze();
1782 let head = frozen.slice(0..3);
1783 let tail = frozen.slice(5..8);
1784 drop(head);
1785 drop(tail);
1786 let mut recovered = frozen.into_mut_with_pool(&pool);
1787 assert_eq!(recovered.as_ref(), b"abcdefgh");
1788 assert_eq!(recovered.as_mut_ptr(), mirror_ptr);
1789 assert_eq!(recovered.capacity(), mirror_cap);
1790 }
1791
1792 #[test]
1793 fn test_iobufmut_additional_conversion_and_trait_paths() {
1794 let mut buf = IoBufMut::from([1u8, 2, 3, 4]);
1796 assert!(!buf.is_empty());
1797 buf.truncate(2);
1798 assert_eq!(buf.as_ref(), &[1u8, 2]);
1799 buf.clear();
1800 assert!(buf.is_empty());
1801 buf.put_slice(b"xyz");
1802
1803 let expected: &[u8] = b"xyz";
1805 assert!(PartialEq::<[u8]>::eq(&buf, expected));
1806 assert!(buf == b"xyz"[..]);
1807 assert!(buf == *b"xyz");
1808 assert!(buf == b"xyz");
1809
1810 let from_array = IoBufMut::from([7u8, 8]);
1812 assert_eq!(from_array.as_ref(), &[7u8, 8]);
1813
1814 let from_bytesmut = IoBufMut::from(BytesMut::from(&b"hi"[..]));
1815 assert_eq!(from_bytesmut.as_ref(), b"hi");
1816
1817 let from_bytes = IoBufMut::from(Bytes::from_static(b"ok"));
1818 assert_eq!(from_bytes.as_ref(), b"ok");
1819
1820 let from_iobuf = IoBufMut::from(IoBuf::from(Bytes::from_static(b"io")));
1822 assert_eq!(from_iobuf.as_ref(), b"io");
1823 }
1824
1825 #[test]
1826 fn test_iobufmut_from_bytesmut_preserves_capacity() {
1827 let mut bytes = BytesMut::with_capacity(100);
1828 bytes.put_slice(b"abc");
1829 let cap = bytes.capacity();
1830 let buf = IoBufMut::from(bytes);
1831 assert_eq!(buf.as_ref(), b"abc");
1832 assert_eq!(buf.capacity(), cap);
1833
1834 let bytes = BytesMut::with_capacity(64);
1836 let cap = bytes.capacity();
1837 let mut buf = IoBufMut::from(bytes);
1838 assert!(buf.is_empty());
1839 assert_eq!(buf.capacity(), cap);
1840 buf.put_bytes(7, cap);
1841 assert_eq!(buf.len(), cap);
1842 }
1843
1844 #[test]
1845 fn test_iobufmut_from_vec_preserves_capacity() {
1846 let mut vec = Vec::with_capacity(100);
1847 vec.extend_from_slice(b"abc");
1848 let buf = IoBufMut::from(vec);
1849 assert_eq!(buf.as_ref(), b"abc");
1850 assert_eq!(buf.capacity(), 100);
1851
1852 let mut buf = IoBufMut::from(Vec::with_capacity(64));
1855 assert!(buf.is_empty());
1856 assert_eq!(buf.capacity(), 64);
1857 buf.put_bytes(7, 64);
1858 assert_eq!(buf.len(), 64);
1859 }
1860
1861 #[test]
1862 #[should_panic(expected = "front heap layout size overflow")]
1863 fn test_iobufmut_with_capacity_rejects_oversized_request() {
1864 let _ = IoBufMut::with_capacity(isize::MAX as usize);
1866 }
1867
1868 #[test]
1869 fn test_iobuf_aligned_public_paths() {
1870 static ARRAY: &[u8; 4] = b"wxyz";
1874
1875 let alignment = NonZeroUsize::new(64).expect("non-zero alignment");
1876
1877 let mut aligned_mut = IoBufMut::with_alignment(8, alignment);
1879 assert!(!aligned_mut.is_pooled());
1880 assert!(aligned_mut.is_empty());
1881 assert_eq!(aligned_mut.capacity(), 8);
1882 assert!((aligned_mut.as_mut_ptr() as usize).is_multiple_of(64));
1883
1884 aligned_mut.put_slice(b"abcdefgh");
1885 assert_eq!(aligned_mut.as_mut(), b"abcdefgh");
1886 assert_eq!(aligned_mut.chunk(), b"abcdefgh");
1887 aligned_mut.advance(2);
1888 assert_eq!(aligned_mut.chunk(), b"cdefgh");
1889
1890 let partial = aligned_mut.copy_to_bytes(2);
1891 assert_eq!(partial.as_ref(), b"cd");
1892 assert_eq!(aligned_mut.as_ref(), b"efgh");
1893 let empty = aligned_mut.copy_to_bytes(0);
1894 assert!(empty.is_empty());
1895 assert_eq!(aligned_mut.as_ref(), b"efgh");
1896
1897 aligned_mut.clear();
1898 assert!(aligned_mut.is_empty());
1899 aligned_mut.put_slice(ARRAY);
1900 assert!(aligned_mut == ARRAY);
1901
1902 let mut fully_drained = IoBufMut::with_alignment(4, alignment);
1904 fully_drained.put_slice(b"lmno");
1905 let empty = fully_drained.copy_to_bytes(0);
1906 assert!(empty.is_empty());
1907 assert_eq!(fully_drained.as_ref(), b"lmno");
1908 let drained = fully_drained.copy_to_bytes(4);
1909 assert_eq!(drained.as_ref(), b"lmno");
1910 assert!(fully_drained.is_empty());
1911
1912 let aligned = aligned_mut.freeze();
1914 assert!(!aligned.is_pooled());
1915 assert_eq!(aligned.as_ref(), &ARRAY[..]);
1916 assert!(aligned == ARRAY);
1917 assert!(!aligned.as_ptr().is_null());
1918 assert_eq!(aligned.slice(..2), b"wx");
1919 assert_eq!(aligned.slice(1..), b"xyz");
1920 assert_eq!(aligned.slice(1..=2), b"xy");
1921 assert_eq!(aligned.chunk(), b"wxyz");
1922
1923 let mut split = aligned.clone();
1924 let prefix = split.split_to(2);
1925 assert_eq!(prefix, b"wx");
1926 assert_eq!(split, b"yz");
1927
1928 let mut advanced = aligned.clone();
1929 advanced.advance(2);
1930 assert_eq!(advanced.chunk(), b"yz");
1931
1932 let mut drained = aligned.clone();
1934 let empty = drained.copy_to_bytes(0);
1935 assert!(empty.is_empty());
1936 assert_eq!(drained.as_ref(), &ARRAY[..]);
1937 let first = drained.copy_to_bytes(1);
1938 assert_eq!(first.as_ref(), b"w");
1939 let rest = drained.copy_to_bytes(3);
1940 assert_eq!(rest.as_ref(), b"xyz");
1941 assert_eq!(drained.remaining(), 0);
1942
1943 let mut unique_source = IoBufMut::zeroed_with_alignment(4, alignment);
1945 unique_source.as_mut().copy_from_slice(b"pqrs");
1946 let unique = unique_source.freeze();
1947 let recovered = unique
1948 .try_into_mut()
1949 .expect("unique aligned iobuf should recover mutability");
1950 assert_eq!(recovered.as_ref(), b"pqrs");
1951
1952 let mut shared_source = IoBufMut::zeroed_with_alignment(4, alignment);
1954 shared_source.as_mut().copy_from_slice(b"tuvw");
1955 let shared = shared_source.freeze();
1956 let _shared_clone = shared.clone();
1957 assert!(shared.try_into_mut().is_err());
1958
1959 let vec_out: Vec<u8> = aligned.clone().into();
1961 let bytes_out: Bytes = aligned.into();
1962 assert_eq!(vec_out, ARRAY.to_vec());
1963 assert_eq!(bytes_out.as_ref(), &ARRAY[..]);
1964
1965 let from_array = IoBuf::from(ARRAY);
1966 assert_eq!(from_array, b"wxyz");
1967
1968 let iobufs = IoBufs::from(ARRAY);
1969 assert_eq!(iobufs.chunk(), b"wxyz");
1970 }
1971
1972 #[test]
1973 fn test_iobufmut_aligned_zero_length_constructors() {
1974 let alignment = NonZeroUsize::new(64).expect("non-zero alignment");
1975
1976 let with_alignment = IoBufMut::with_alignment(0, alignment);
1977 assert!(with_alignment.is_empty());
1978 assert_eq!(with_alignment.len(), 0);
1979 assert_eq!(with_alignment.capacity(), 0);
1980
1981 let zeroed = IoBufMut::zeroed_with_alignment(0, alignment);
1982 assert!(zeroed.is_empty());
1983 assert_eq!(zeroed.len(), 0);
1984 assert_eq!(zeroed.capacity(), 0);
1985
1986 let invalid_alignment = NonZeroUsize::new(3).expect("non-zero alignment");
1988 assert_eq!(IoBufMut::with_alignment(0, invalid_alignment).capacity(), 0);
1989 assert_eq!(
1990 IoBufMut::zeroed_with_alignment(0, invalid_alignment).capacity(),
1991 0
1992 );
1993 }
1994
1995 #[test]
1996 fn test_iobufmut_aligned_capacity_stable_across_recovery() {
1997 let alignment = NonZeroUsize::new(4096).expect("non-zero alignment");
2001 let mut buf = IoBufMut::with_alignment(100, alignment);
2002 assert_eq!(buf.capacity(), 104);
2003
2004 buf.put_slice(b"data");
2005 let recovered = buf
2006 .freeze()
2007 .try_into_mut()
2008 .expect("unique native view recovers");
2009 assert_eq!(recovered.capacity(), 104);
2010
2011 let zeroed = IoBufMut::zeroed_with_alignment(100, alignment);
2014 assert_eq!(zeroed.len(), 100);
2015 assert_eq!(zeroed.capacity(), 104);
2016
2017 let exact = IoBufMut::with_alignment(128, alignment);
2019 assert_eq!(exact.capacity(), 128);
2020 }
2021
2022 #[test]
2023 #[should_panic(expected = "set_len(9) exceeds capacity(8)")]
2024 fn test_iobufmut_set_len_overflow() {
2025 let mut buf = IoBufMut::with_capacity(8);
2026 unsafe { buf.set_len(9) };
2028 }
2029
2030 #[cfg(feature = "arbitrary")]
2031 mod conformance {
2032 use super::IoBuf;
2033 use commonware_codec::conformance::CodecConformance;
2034
2035 commonware_conformance::conformance_tests! {
2036 CodecConformance<IoBuf>
2037 }
2038 }
2039}