1use super::{
10 owner::{Descriptor, Owner, OwnerCell, Storage},
11 panic_advance,
12};
13use bytes::{BufMut, Bytes, BytesMut, TryGetError};
14use commonware_codec::{Buf, BufsMut, EncodeSize, Error, Input, OwnedBytes, RangeCfg, Read, Write};
15use std::{
16 alloc::Layout,
17 mem::ManuallyDrop,
18 num::NonZeroUsize,
19 ops::{Bound, RangeBounds},
20 ptr::NonNull,
21};
22
23pub struct IoBuf {
47 ptr: NonNull<u8>,
48 len: usize,
49 owner: OwnerCell,
50}
51
52#[cfg(not(feature = "loom"))]
54const _: () = assert!(size_of::<IoBuf>() == 3 * size_of::<usize>());
55
56unsafe impl Send for IoBuf {}
59unsafe impl Sync for IoBuf {}
61
62impl std::fmt::Debug for IoBuf {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("IoBuf").field("len", &self.len).finish()
67 }
68}
69
70impl Clone for IoBuf {
71 #[inline]
72 fn clone(&self) -> Self {
73 let owner = self.retain();
74 Self {
75 ptr: self.ptr,
76 len: self.len,
77 owner: OwnerCell::new(owner),
78 }
79 }
80}
81
82impl Drop for IoBuf {
83 #[inline]
84 fn drop(&mut self) {
85 let owner = self.owner.get();
92 if unsafe { owner.drop_view() } {
94 unsafe { owner.release_unique(self.ptr, self.len) };
97 }
98 }
99}
100
101impl IoBuf {
102 #[inline(always)]
108 fn retain(&self) -> Owner {
109 let owner = self.owner.load();
110 if let Some(descriptor) = owner.descriptor() {
111 return unsafe { self.promote(descriptor) };
113 }
114 unsafe { owner.clone_shared() };
117 owner
118 }
119
120 #[cold]
136 #[inline(never)]
137 unsafe fn promote(&self, descriptor: Descriptor) -> Owner {
138 unsafe { self.owner.promote(descriptor, self.ptr, self.len) }
141 }
142
143 pub fn copy_from_slice(data: &[u8]) -> Self {
151 IoBufMut::from(data).freeze()
152 }
153
154 #[inline]
155 fn from_static(slice: &'static [u8]) -> Self {
156 if slice.is_empty() {
157 return Self::default();
158 }
159 let ptr = NonNull::new(slice.as_ptr().cast_mut()).expect("static slice data is non-null");
160 Self {
161 ptr,
162 len: slice.len(),
163 owner: OwnerCell::empty(),
164 }
165 }
166
167 #[inline]
169 pub const fn len(&self) -> usize {
170 self.len
171 }
172
173 #[inline]
175 pub const fn is_empty(&self) -> bool {
176 self.len == 0
177 }
178
179 #[inline]
181 pub const fn as_ptr(&self) -> *const u8 {
182 self.ptr.as_ptr()
183 }
184
185 #[inline]
195 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
196 let (start, end) = resolve_range(self.len, range);
197 if start == end {
198 return Self::default();
199 }
200
201 let owner = self.retain();
202 Self {
203 ptr: unsafe { self.ptr.add(start) },
205 len: end - start,
206 owner: OwnerCell::new(owner),
207 }
208 }
209
210 #[inline(always)]
228 pub fn split_to(&mut self, at: usize) -> Self {
229 if at > self.len {
230 panic_split_to(at, self.len);
231 }
232 if at == 0 {
233 return Self::default();
234 }
235 if at == self.len {
236 return std::mem::take(self);
237 }
238
239 let (ptr, len) = (self.ptr, self.len);
240 let owner = unsafe { self.owner.retain_mut(ptr, len) };
243 self.ptr = unsafe { ptr.add(at) };
245 self.len = len - at;
246 Self {
247 ptr,
248 len: at,
249 owner: OwnerCell::new(owner),
250 }
251 }
252
253 #[inline]
265 pub fn try_into_mut(mut self) -> Result<IoBufMut, Self> {
266 let owner = self.owner.get();
267 if let Some(descriptor) = owner.descriptor() {
268 let cap = self.len.wrapping_add(descriptor.tail());
272 let me = ManuallyDrop::new(self);
273 return Ok(IoBufMut {
274 ptr: me.ptr,
275 len: me.len,
276 cap,
277 owner: descriptor.without_tail().into(),
278 });
279 }
280 if owner.is_empty() {
281 return if self.len == 0 {
282 Ok(IoBufMut::default())
283 } else {
284 Err(self)
285 };
286 }
287
288 let Some(&Storage::Native { base, layout }) = (unsafe { owner.storage() }) else {
291 return Err(self);
292 };
293
294 if !unsafe { owner.is_unique() } {
296 return Err(self);
297 }
298
299 let me = ManuallyDrop::new(self);
300 let offset = (me.ptr.as_ptr() as usize)
301 .checked_sub(base.as_ptr() as usize)
302 .expect("view pointer must be within owner allocation");
303 assert!(
304 offset <= layout.size(),
305 "view pointer must be within owner bounds"
306 );
307 let cap = layout.size() - offset;
308 assert!(me.len <= cap, "view length must be within owner bounds");
309
310 Ok(IoBufMut {
311 ptr: me.ptr,
312 len: me.len,
313 cap,
314 owner,
315 })
316 }
317
318 #[cfg(all(test, feature = "loom"))]
320 pub(crate) const fn owner_cell(&self) -> &OwnerCell {
321 &self.owner
322 }
323}
324
325impl AsRef<[u8]> for IoBuf {
326 #[inline]
327 fn as_ref(&self) -> &[u8] {
328 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
331 }
332}
333
334impl Default for IoBuf {
335 fn default() -> Self {
336 Self {
337 ptr: NonNull::dangling(),
338 len: 0,
339 owner: OwnerCell::empty(),
340 }
341 }
342}
343
344impl PartialEq for IoBuf {
345 fn eq(&self, other: &Self) -> bool {
346 self.as_ref() == other.as_ref()
347 }
348}
349
350impl Eq for IoBuf {}
351
352impl PartialEq<[u8]> for IoBuf {
353 #[inline]
354 fn eq(&self, other: &[u8]) -> bool {
355 self.as_ref() == other
356 }
357}
358
359impl PartialEq<&[u8]> for IoBuf {
360 #[inline]
361 fn eq(&self, other: &&[u8]) -> bool {
362 self.as_ref() == *other
363 }
364}
365
366impl<const N: usize> PartialEq<[u8; N]> for IoBuf {
367 #[inline]
368 fn eq(&self, other: &[u8; N]) -> bool {
369 self.as_ref() == other
370 }
371}
372
373impl<const N: usize> PartialEq<&[u8; N]> for IoBuf {
374 #[inline]
375 fn eq(&self, other: &&[u8; N]) -> bool {
376 self.as_ref() == *other
377 }
378}
379
380impl Buf for IoBuf {
381 #[inline]
384 fn take_owned<T: OwnedBytes>(&mut self, len: usize) -> T {
385 T::claim(self.split_to(len)).unwrap_or_else(|view| T::from_bytes(view.into()))
386 }
387}
388
389impl OwnedBytes for IoBuf {
390 #[inline]
391 fn from_bytes(bytes: Bytes) -> Self {
392 Self::from(bytes)
393 }
394}
395
396impl bytes::Buf for IoBuf {
397 #[inline(always)]
398 fn remaining(&self) -> usize {
399 self.len
400 }
401
402 #[inline(always)]
403 fn chunk(&self) -> &[u8] {
404 self.as_ref()
405 }
406
407 #[inline(always)]
408 fn advance(&mut self, cnt: usize) {
409 if cnt > self.len {
410 panic_advance(cnt, self.len);
411 }
412 unsafe {
415 self.ptr = self.ptr.add(cnt);
416 }
417 self.len -= cnt;
418 }
419
420 #[inline]
421 fn copy_to_slice(&mut self, dst: &mut [u8]) {
422 if let Err(error) = self.try_copy_to_slice(dst) {
423 panic_try_get(error);
424 }
425 }
426
427 #[inline]
428 fn try_copy_to_slice(&mut self, dst: &mut [u8]) -> Result<(), TryGetError> {
429 if dst.len() > self.len {
430 return Err(TryGetError {
431 requested: dst.len(),
432 available: self.len,
433 });
434 }
435 unsafe {
439 std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), dst.as_mut_ptr(), dst.len());
440 self.ptr = self.ptr.add(dst.len());
441 }
442 self.len -= dst.len();
443 Ok(())
444 }
445
446 #[inline]
453 fn copy_to_bytes(&mut self, len: usize) -> Bytes {
454 assert!(len <= self.len, "copy_to_bytes out of bounds");
455 if len == 0 {
456 return Bytes::new();
457 }
458 if len == self.len {
459 return Bytes::from(std::mem::take(self));
460 }
461
462 let owner = self.owner.get();
465 if owner.descriptor().is_none()
466 && let Some(Storage::External(inner)) = unsafe { owner.storage() }
468 {
469 let bytes = inner.slice_ref(&self.as_ref()[..len]);
472 self.advance(len);
473 return bytes;
474 }
475
476 Bytes::from(self.split_to(len))
477 }
478}
479
480impl From<Vec<u8>> for IoBuf {
485 #[inline]
486 fn from(vec: Vec<u8>) -> Self {
487 IoBufMut::from(vec).freeze()
488 }
489}
490
491impl From<Bytes> for IoBuf {
498 fn from(bytes: Bytes) -> Self {
499 if bytes.is_empty() {
500 return Self::default();
501 }
502 let ptr = NonNull::new(bytes.as_ptr().cast_mut())
503 .expect("non-empty Bytes must have non-null data");
504 Self {
505 ptr,
506 len: bytes.len(),
507 owner: OwnerCell::new(Owner::new(Storage::External(bytes))),
508 }
509 }
510}
511
512impl From<BytesMut> for IoBuf {
514 fn from(bytes: BytesMut) -> Self {
515 Self::from(bytes.freeze())
516 }
517}
518
519impl From<IoBufMut> for IoBuf {
521 #[inline]
522 fn from(buf: IoBufMut) -> Self {
523 buf.freeze()
524 }
525}
526
527impl<const N: usize> From<&'static [u8; N]> for IoBuf {
529 #[inline]
530 fn from(array: &'static [u8; N]) -> Self {
531 Self::from_static(array)
532 }
533}
534
535impl From<&'static [u8]> for IoBuf {
537 #[inline]
538 fn from(slice: &'static [u8]) -> Self {
539 Self::from_static(slice)
540 }
541}
542
543impl From<IoBuf> for Vec<u8> {
547 fn from(buf: IoBuf) -> Self {
548 buf.as_ref().to_vec()
549 }
550}
551
552impl From<IoBuf> for Bytes {
561 fn from(mut buf: IoBuf) -> Self {
562 if buf.is_empty() {
563 return Self::new();
564 }
565 let owner = buf.owner.get();
566 if owner.descriptor().is_none() {
567 if owner.is_empty() {
568 let slice: &'static [u8] =
571 unsafe { std::slice::from_raw_parts(buf.ptr.as_ptr(), buf.len) };
572 return Self::from_static(slice);
573 }
574
575 if let Some(Storage::External(inner)) = unsafe { owner.storage() } {
579 return inner.slice_ref(buf.as_ref());
580 }
581 }
582
583 let buf = ManuallyDrop::new(buf);
586 unsafe { owner.into_bytes(buf.ptr, buf.len) }
589 }
590}
591
592impl Write for IoBuf {
593 #[inline]
594 fn write(&self, buf: &mut impl BufMut) {
595 self.len().write(buf);
596 buf.put_slice(self.as_ref());
597 }
598
599 #[inline]
600 fn write_bufs(&self, buf: &mut impl BufsMut) {
601 self.len().write(buf);
602 buf.push(self.clone());
603 }
604}
605
606impl EncodeSize for IoBuf {
607 #[inline]
608 fn encode_size(&self) -> usize {
609 self.len().encode_size() + self.len()
610 }
611
612 #[inline]
613 fn encode_inline_size(&self) -> usize {
614 self.len().encode_size()
615 }
616}
617
618impl Read for IoBuf {
619 type Cfg = RangeCfg<usize>;
620
621 #[inline]
622 fn read_cfg(buf: &mut impl Buf, range: &Self::Cfg) -> Result<Self, Error> {
623 let len = usize::read_cfg(buf, range)?;
624 buf.try_take_owned(len).map_err(|_| Error::EndOfBuffer)
625 }
626}
627
628#[cfg(feature = "arbitrary")]
629impl arbitrary::Arbitrary<'_> for IoBuf {
630 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
631 let len = u.arbitrary_len::<u8>()?;
632 let data: Vec<u8> = u.arbitrary_iter()?.take(len).collect::<Result<_, _>>()?;
633 Ok(Self::from(data))
634 }
635}
636
637pub struct IoBufMut {
666 ptr: NonNull<u8>,
667 len: usize,
668 cap: usize,
669 owner: Owner,
670}
671
672const _: () = assert!(size_of::<IoBufMut>() == 4 * size_of::<usize>());
674
675unsafe impl Send for IoBufMut {}
678unsafe impl Sync for IoBufMut {}
681
682impl std::fmt::Debug for IoBufMut {
685 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
686 f.debug_struct("IoBufMut")
687 .field("len", &self.len)
688 .field("cap", &self.cap)
689 .finish()
690 }
691}
692
693impl Drop for IoBufMut {
694 #[inline]
695 fn drop(&mut self) {
696 unsafe { self.owner.release_unique(self.ptr, self.cap) };
699 }
700}
701
702impl Default for IoBufMut {
703 fn default() -> Self {
704 Self {
705 ptr: NonNull::dangling(),
706 len: 0,
707 cap: 0,
708 owner: Owner::empty(),
709 }
710 }
711}
712
713impl IoBufMut {
714 #[inline]
717 pub fn with_capacity(capacity: usize) -> Self {
718 Self::with_alignment(capacity, NonZeroUsize::MIN)
719 }
720
721 #[inline]
729 pub fn with_alignment(capacity: usize, alignment: NonZeroUsize) -> Self {
730 Self::try_with_alignment(capacity, alignment)
731 .expect("alignment must be a power of two and the size must fit a layout")
732 }
733
734 #[inline]
742 pub(crate) fn try_with_alignment(capacity: usize, alignment: NonZeroUsize) -> Option<Self> {
743 if capacity == 0 {
744 return Some(Self::default());
745 }
746 Layout::from_size_align(capacity, alignment.get()).ok()?;
747 let (ptr, owner) = Owner::allocate(capacity, alignment.get(), false);
748 Some(Self {
749 ptr,
750 len: 0,
751 cap: capacity,
752 owner,
753 })
754 }
755
756 #[inline]
767 pub fn zeroed_with_alignment(len: usize, alignment: NonZeroUsize) -> Self {
768 if len == 0 {
769 return Self::default();
770 }
771 let (ptr, owner) = Owner::allocate(len, alignment.get(), true);
772 Self {
773 ptr,
774 len,
775 cap: len,
776 owner,
777 }
778 }
779
780 #[inline]
786 pub fn zeroed(len: usize) -> Self {
787 Self::zeroed_with_alignment(len, NonZeroUsize::MIN)
788 }
789
790 #[inline]
801 pub unsafe fn set_len(&mut self, len: usize) {
802 assert!(
803 len <= self.capacity(),
804 "set_len({len}) exceeds capacity({})",
805 self.capacity()
806 );
807 self.len = len;
808 }
809
810 #[inline]
812 pub const fn len(&self) -> usize {
813 self.len
814 }
815
816 #[inline]
818 pub const fn is_empty(&self) -> bool {
819 self.len == 0
820 }
821
822 #[inline]
831 pub fn freeze(self) -> IoBuf {
832 if self.len == 0 {
833 drop(self);
835 return IoBuf::default();
836 }
837 let owner = unsafe { self.owner.frozen(self.ptr, self.len, self.cap) };
841 let me = ManuallyDrop::new(self);
843 IoBuf {
844 ptr: me.ptr,
845 len: me.len,
846 owner: OwnerCell::new(owner),
847 }
848 }
849
850 #[inline]
853 pub const fn capacity(&self) -> usize {
854 self.cap
855 }
856
857 #[inline]
859 pub const fn as_mut_ptr(&mut self) -> *mut u8 {
860 self.ptr.as_ptr()
861 }
862
863 #[inline]
867 pub fn truncate(&mut self, len: usize) {
868 self.len = self.len.min(len);
869 }
870
871 #[inline]
873 pub const fn clear(&mut self) {
874 self.len = 0;
875 }
876}
877
878impl AsRef<[u8]> for IoBufMut {
879 #[inline]
880 fn as_ref(&self) -> &[u8] {
881 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
883 }
884}
885
886impl AsMut<[u8]> for IoBufMut {
887 #[inline]
888 fn as_mut(&mut self) -> &mut [u8] {
889 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
892 }
893}
894
895impl PartialEq<[u8]> for IoBufMut {
896 #[inline]
897 fn eq(&self, other: &[u8]) -> bool {
898 self.as_ref() == other
899 }
900}
901
902impl PartialEq<&[u8]> for IoBufMut {
903 #[inline]
904 fn eq(&self, other: &&[u8]) -> bool {
905 self.as_ref() == *other
906 }
907}
908
909impl<const N: usize> PartialEq<[u8; N]> for IoBufMut {
910 #[inline]
911 fn eq(&self, other: &[u8; N]) -> bool {
912 self.as_ref() == other
913 }
914}
915
916impl<const N: usize> PartialEq<&[u8; N]> for IoBufMut {
917 #[inline]
918 fn eq(&self, other: &&[u8; N]) -> bool {
919 self.as_ref() == *other
920 }
921}
922
923impl Input for IoBufMut {
924 type Buf = IoBuf;
925}
926
927impl bytes::Buf for IoBufMut {
928 #[inline(always)]
929 fn remaining(&self) -> usize {
930 self.len
931 }
932
933 #[inline(always)]
934 fn chunk(&self) -> &[u8] {
935 self.as_ref()
936 }
937
938 #[inline(always)]
939 fn advance(&mut self, cnt: usize) {
940 if cnt > self.len {
941 panic_advance(cnt, self.len);
942 }
943 unsafe {
947 self.ptr = self.ptr.add(cnt);
948 }
949 self.len -= cnt;
950 self.cap -= cnt;
951 }
952
953 #[inline]
954 fn copy_to_slice(&mut self, dst: &mut [u8]) {
955 if let Err(error) = self.try_copy_to_slice(dst) {
956 panic_try_get(error);
957 }
958 }
959
960 #[inline]
961 fn try_copy_to_slice(&mut self, dst: &mut [u8]) -> Result<(), TryGetError> {
962 if dst.len() > self.len {
963 return Err(TryGetError {
964 requested: dst.len(),
965 available: self.len,
966 });
967 }
968 unsafe {
973 std::ptr::copy_nonoverlapping(self.ptr.as_ptr(), dst.as_mut_ptr(), dst.len());
974 self.ptr = self.ptr.add(dst.len());
975 }
976 self.len -= dst.len();
977 self.cap -= dst.len();
978 Ok(())
979 }
980
981 #[inline]
989 fn copy_to_bytes(&mut self, len: usize) -> Bytes {
990 assert!(len <= self.len, "copy_to_bytes out of bounds");
991 if len == 0 {
992 return Bytes::new();
993 }
994 if len == self.len {
995 let drained = std::mem::take(self);
996 return Bytes::from(drained.freeze());
997 }
998
999 let bytes = Bytes::copy_from_slice(&self.as_ref()[..len]);
1000 self.advance(len);
1001 bytes
1002 }
1003}
1004
1005unsafe impl BufMut for IoBufMut {
1008 #[inline(always)]
1009 fn remaining_mut(&self) -> usize {
1010 self.cap - self.len
1011 }
1012
1013 #[inline(always)]
1014 unsafe fn advance_mut(&mut self, cnt: usize) {
1015 let writable = self.cap - self.len;
1016 if cnt > writable {
1017 panic_advance(cnt, writable);
1018 }
1019 self.len += cnt;
1020 }
1021
1022 #[inline(always)]
1023 fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
1024 unsafe {
1027 let ptr = self.ptr.as_ptr().add(self.len);
1028 bytes::buf::UninitSlice::from_raw_parts_mut(ptr, self.cap - self.len)
1029 }
1030 }
1031
1032 #[inline]
1033 fn put_slice(&mut self, src: &[u8]) {
1034 let writable = self.cap - self.len;
1035 if src.len() > writable {
1036 panic_advance(src.len(), writable);
1037 }
1038 unsafe {
1040 std::ptr::copy_nonoverlapping(src.as_ptr(), self.ptr.as_ptr().add(self.len), src.len());
1041 }
1042 self.len += src.len();
1043 }
1044
1045 #[inline]
1046 fn put_bytes(&mut self, val: u8, cnt: usize) {
1047 let writable = self.cap - self.len;
1048 if cnt > writable {
1049 panic_advance(cnt, writable);
1050 }
1051 unsafe {
1053 std::ptr::write_bytes(self.ptr.as_ptr().add(self.len), val, cnt);
1054 }
1055 self.len += cnt;
1056 }
1057
1058 #[inline]
1059 fn put<T: bytes::Buf>(&mut self, mut src: T)
1060 where
1061 Self: Sized,
1062 {
1063 let remaining = src.remaining();
1065 if remaining > self.cap - self.len {
1066 panic_advance(remaining, self.cap - self.len);
1067 }
1068 while src.has_remaining() {
1069 let chunk = src.chunk();
1070 let cnt = chunk.len();
1071 let writable = self.cap - self.len;
1075 if cnt > writable {
1076 panic_advance(cnt, writable);
1077 }
1078 unsafe {
1080 std::ptr::copy_nonoverlapping(chunk.as_ptr(), self.ptr.as_ptr().add(self.len), cnt);
1081 }
1082 self.len += cnt;
1083 src.advance(cnt);
1084 }
1085 }
1086}
1087
1088impl From<&[u8]> for IoBufMut {
1090 fn from(slice: &[u8]) -> Self {
1091 let mut buf = Self::with_capacity(slice.len());
1092 buf.put_slice(slice);
1093 buf
1094 }
1095}
1096
1097impl<const N: usize> From<[u8; N]> for IoBufMut {
1099 fn from(array: [u8; N]) -> Self {
1100 Self::from(array.as_ref())
1101 }
1102}
1103
1104impl<const N: usize> From<&[u8; N]> for IoBufMut {
1106 fn from(array: &[u8; N]) -> Self {
1107 Self::from(array.as_ref())
1108 }
1109}
1110
1111impl From<Vec<u8>> for IoBufMut {
1117 #[inline]
1118 fn from(vec: Vec<u8>) -> Self {
1119 if vec.capacity() == 0 {
1120 return Self::default();
1121 }
1122 let (ptr, len, cap, owner) = Owner::adopt_vec(vec);
1123 Self {
1124 ptr,
1125 len,
1126 cap,
1127 owner,
1128 }
1129 }
1130}
1131
1132impl From<BytesMut> for IoBufMut {
1139 fn from(bytes: BytesMut) -> Self {
1140 let capacity = bytes.capacity();
1141 let mut vec = Vec::from(bytes);
1142 if vec.capacity() < capacity {
1143 vec.reserve_exact(capacity - vec.len());
1144 }
1145 Self::from(vec)
1146 }
1147}
1148
1149impl From<Bytes> for IoBufMut {
1157 fn from(bytes: Bytes) -> Self {
1158 Self::from(Vec::from(bytes))
1159 }
1160}
1161
1162impl From<IoBuf> for IoBufMut {
1165 fn from(buf: IoBuf) -> Self {
1166 match buf.try_into_mut() {
1167 Ok(buf) => buf,
1168 Err(buf) => Self::from(buf.as_ref()),
1169 }
1170 }
1171}
1172
1173#[cold]
1178#[inline(never)]
1179fn panic_split_to(at: usize, len: usize) -> ! {
1180 panic!("split_to out of bounds: {at:?} <= {len:?}");
1181}
1182
1183#[cold]
1186#[inline(never)]
1187fn panic_try_get(error: TryGetError) -> ! {
1188 panic!("{error}");
1189}
1190
1191fn resolve_range(len: usize, range: impl RangeBounds<usize>) -> (usize, usize) {
1196 let start = match range.start_bound() {
1197 Bound::Included(&n) => n,
1198 Bound::Excluded(&n) => n.checked_add(1).expect("range start overflow"),
1199 Bound::Unbounded => 0,
1200 };
1201 let end = match range.end_bound() {
1202 Bound::Included(&n) => n.checked_add(1).expect("range end overflow"),
1203 Bound::Excluded(&n) => n,
1204 Bound::Unbounded => len,
1205 };
1206 assert!(start <= end, "slice start must be <= end");
1207 assert!(end <= len, "slice out of bounds");
1208 (start, end)
1209}
1210
1211#[cfg(all(test, not(feature = "loom")))]
1212#[commonware_macros::test_group("miri")]
1213mod unit_tests {
1214 use super::{super::bufs::IoBufs, *};
1215 use bytes::{Buf as _, Bytes, BytesMut};
1216 use commonware_codec::{Decode, Encode, RangeCfg};
1217 use core::ops::Bound;
1218 use std::panic::{RefUnwindSafe, UnwindSafe};
1219
1220 fn is_native(buf: &IoBuf) -> bool {
1223 let owner = buf.owner.load();
1224 owner.descriptor().is_some()
1225 || matches!(unsafe { owner.storage() }, Some(Storage::Native { .. }))
1227 }
1228
1229 fn is_unshared(buf: &IoBuf) -> bool {
1231 buf.owner.load().descriptor().is_some()
1232 }
1233
1234 fn record(buf: &IoBuf) -> Option<(usize, usize)> {
1236 let owner = buf.owner.load();
1237 if owner.descriptor().is_some() {
1238 return None;
1239 }
1240 unsafe {
1243 let addr = owner.storage()?;
1244 Some((std::ptr::from_ref(addr).addr(), owner.refcount()?))
1245 }
1246 }
1247
1248 fn refcount(buf: &IoBuf) -> Option<usize> {
1250 record(buf).map(|(_, refs)| refs)
1251 }
1252
1253 fn unshared(len: usize, cap: usize) -> IoBuf {
1256 let mut buf = IoBufMut::with_capacity(cap);
1257 for byte in 0..len {
1258 buf.put_u8(byte as u8);
1259 }
1260 let buf = buf.freeze();
1261 assert!(is_unshared(&buf));
1262 buf
1263 }
1264
1265 #[test]
1266 fn test_iobuf_core_behaviors() {
1267 let buf1 = IoBuf::from(vec![1u8; 1000]);
1269 let buf2 = buf1.clone();
1270 assert_eq!(buf1.as_ref().as_ptr(), buf2.as_ref().as_ptr());
1271
1272 let data = vec![1u8, 2, 3, 4, 5];
1274 let copied = IoBuf::copy_from_slice(&data);
1275 assert_eq!(copied, [1, 2, 3, 4, 5]);
1276 assert_eq!(copied.len(), 5);
1277 let empty = IoBuf::copy_from_slice(&[]);
1278 assert!(empty.is_empty());
1279
1280 let eq = IoBuf::from(b"hello");
1282 assert_eq!(eq, *b"hello");
1283 assert_eq!(eq, b"hello");
1284 assert_ne!(eq, *b"world");
1285 assert_ne!(eq, b"world");
1286 assert_eq!(IoBuf::from(b"hello"), IoBuf::from(b"hello"));
1287 assert_ne!(IoBuf::from(b"hello"), IoBuf::from(b"world"));
1288 let bytes: Bytes = IoBuf::from(b"bytes").into();
1289 assert_eq!(bytes.as_ref(), b"bytes");
1290
1291 let mut buf = IoBuf::from(b"hello world");
1293 assert_eq!(buf.len(), buf.remaining());
1294 assert_eq!(buf.as_ref(), buf.chunk());
1295 assert_eq!(buf.remaining(), 11);
1296 buf.advance(6);
1297 assert_eq!(buf.chunk(), b"world");
1298 assert_eq!(buf.len(), buf.remaining());
1299
1300 let first = buf.copy_to_bytes(2);
1302 assert_eq!(&first[..], b"wo");
1303 let rest = buf.copy_to_bytes(3);
1304 assert_eq!(&rest[..], b"rld");
1305 assert_eq!(buf.remaining(), 0);
1306
1307 let src = IoBuf::from(b"hello world");
1309 assert_eq!(src.slice(..5), b"hello");
1310 assert_eq!(src.slice(6..), b"world");
1311 assert_eq!(src.slice(3..8), b"lo wo");
1312 assert!(src.slice(5..5).is_empty());
1313 }
1314
1315 #[test]
1316 fn test_iobuf_from_conversions_are_zero_copy() {
1317 let mut vec = Vec::with_capacity(128);
1322 vec.extend_from_slice(b"adopt");
1323 let ptr = vec.as_ptr();
1324 let buf = IoBuf::from(vec);
1325 assert_eq!(buf.as_ref().as_ptr(), ptr);
1326
1327 let vec = b"exact".to_vec();
1330 let ptr = vec.as_ptr();
1331 let buf = IoBuf::from(vec);
1332 assert_eq!(buf.as_ref().as_ptr(), ptr);
1333 assert_eq!(Bytes::from(buf).as_ptr(), ptr);
1334
1335 let bytes = Bytes::from(b"bytes".to_vec());
1337 let ptr = bytes.as_ptr();
1338 let buf = IoBuf::from(bytes);
1339 assert_eq!(buf.as_ref().as_ptr(), ptr);
1340
1341 let mut bytes = BytesMut::with_capacity(16);
1343 bytes.put_slice(b"frozen");
1344 let ptr = bytes.as_ref().as_ptr();
1345 let buf = IoBuf::from(bytes);
1346 assert_eq!(buf.as_ref().as_ptr(), ptr);
1347
1348 static DATA: [u8; 4] = *b"data";
1350 let buf = IoBuf::from(&DATA[..]);
1351 assert_eq!(buf.as_ref().as_ptr(), DATA.as_ptr());
1352 }
1353
1354 #[test]
1355 fn test_iobuf_codec_roundtrip() {
1356 let cfg: RangeCfg<usize> = (0..=1024).into();
1357
1358 let original = IoBuf::from(b"hello world");
1359 let encoded = original.encode();
1360 let decoded = IoBuf::decode_cfg(encoded, &cfg).unwrap();
1361 assert_eq!(original, decoded);
1362
1363 let empty = IoBuf::default();
1364 let encoded = empty.encode();
1365 let decoded = IoBuf::decode_cfg(encoded, &cfg).unwrap();
1366 assert_eq!(empty, decoded);
1367
1368 let large_cfg: RangeCfg<usize> = (0..=20000).into();
1369 let large = IoBuf::from(vec![42u8; 10000]);
1370 let encoded = large.encode();
1371 let decoded = IoBuf::decode_cfg(encoded, &large_cfg).unwrap();
1372 assert_eq!(large, decoded);
1373
1374 let mut truncated = BytesMut::new();
1375 4usize.write(&mut truncated);
1376 truncated.extend_from_slice(b"xy");
1377 let mut truncated = truncated.freeze();
1378 assert!(matches!(
1379 IoBuf::read_cfg(&mut truncated, &cfg),
1380 Err(Error::EndOfBuffer)
1381 ));
1382
1383 let mut direct = BytesMut::new();
1385 4usize.write(&mut direct);
1386 direct.extend_from_slice(b"wxyz");
1387 let mut direct = direct.freeze();
1388 let decoded = IoBuf::read_cfg(&mut direct, &cfg).unwrap();
1389 assert_eq!(decoded, b"wxyz");
1390 }
1391
1392 #[test]
1393 #[should_panic(expected = "cannot advance")]
1394 fn test_iobuf_advance_past_end() {
1395 let mut buf = IoBuf::from(b"hello");
1396 buf.advance(10);
1397 }
1398
1399 #[test]
1400 fn test_iobuf_copy_to_slice_paths() {
1401 let mut buf = IoBuf::from(b"hello world");
1402 let mut dst = [0u8; 5];
1403 buf.copy_to_slice(&mut dst);
1404 assert_eq!(&dst, b"hello");
1405 assert_eq!(buf.as_ref(), b" world");
1406
1407 let mut dst = [0u8; 3];
1408 buf.try_copy_to_slice(&mut dst).unwrap();
1409 assert_eq!(&dst, b" wo");
1410
1411 let mut dst = [0u8; 4];
1413 let err = buf.try_copy_to_slice(&mut dst).unwrap_err();
1414 assert_eq!(err.requested, 4);
1415 assert_eq!(err.available, 3);
1416 assert_eq!(buf.as_ref(), b"rld");
1417 }
1418
1419 #[test]
1420 #[should_panic(expected = "Not enough bytes remaining in buffer")]
1421 fn test_iobuf_copy_to_slice_past_end() {
1422 let mut buf = IoBuf::from(b"ab");
1423 let mut dst = [0u8; 3];
1424 buf.copy_to_slice(&mut dst);
1425 }
1426
1427 #[test]
1428 #[should_panic(expected = "copy_to_bytes out of bounds")]
1429 fn test_iobuf_copy_to_bytes_past_end() {
1430 let mut buf = IoBuf::from(b"ab");
1431 let _ = buf.copy_to_bytes(3);
1432 }
1433
1434 #[test]
1435 fn test_iobuf_slice_excluded_start_bound() {
1436 let buf = IoBuf::from(b"hello");
1438 let sliced = buf.slice((Bound::Excluded(0), Bound::Unbounded));
1439 assert_eq!(sliced, b"ello");
1440 }
1441
1442 #[test]
1443 #[should_panic(expected = "slice out of bounds")]
1444 fn test_iobuf_slice_out_of_bounds() {
1445 let buf = IoBuf::from(b"hello");
1446 let _ = buf.slice(..6);
1447 }
1448
1449 #[test]
1450 #[should_panic(expected = "slice start must be <= end")]
1451 fn test_iobuf_slice_inverted_range() {
1452 let buf = IoBuf::from(b"hello");
1453 #[allow(clippy::reversed_empty_ranges)]
1454 let _ = buf.slice(3..1);
1455 }
1456
1457 #[test]
1458 #[should_panic(expected = "range end overflow")]
1459 fn test_iobuf_slice_inclusive_end_overflow() {
1460 let buf = IoBuf::from(b"hello");
1461 let _ = buf.slice(0..=usize::MAX);
1462 }
1463
1464 #[test]
1465 #[should_panic(expected = "range start overflow")]
1466 fn test_iobuf_slice_excluded_start_overflow() {
1467 let buf = IoBuf::from(b"hello");
1468 let _ = buf.slice((Bound::Excluded(usize::MAX), Bound::Unbounded));
1469 }
1470
1471 #[test]
1472 fn test_iobuf_try_into_mut_empty_and_static() {
1473 let buf = IoBuf::default().try_into_mut().expect("empty converts");
1475 assert!(buf.is_empty());
1476 assert_eq!(buf.capacity(), 0);
1477
1478 let err = IoBuf::from(b"static").try_into_mut().unwrap_err();
1481 assert_eq!(err, b"static");
1482
1483 let empty = Bytes::from(IoBuf::default());
1485 assert!(empty.is_empty());
1486
1487 let empty = IoBuf::from(&b""[..]);
1489 assert!(empty.is_empty());
1490 assert!(empty.try_into_mut().is_ok());
1491 }
1492
1493 #[test]
1494 fn test_iobuf_split_to_consistent_across_backings() {
1495 let mut native = IoBufMut::with_capacity(256);
1497 native.put_slice(b"hello world");
1498 let mut native_buf = native.freeze();
1499 let mut bytes_buf = IoBuf::from(b"hello world");
1500
1501 let native_empty = native_buf.split_to(0);
1502 let bytes_empty = bytes_buf.split_to(0);
1503 assert_eq!(native_empty, bytes_empty);
1504 assert_eq!(native_buf, bytes_buf);
1505
1506 let native_prefix = native_buf.split_to(5);
1507 let bytes_prefix = bytes_buf.split_to(5);
1508 assert_eq!(native_prefix, bytes_prefix);
1509 assert_eq!(native_buf, bytes_buf);
1510
1511 let native_rest = native_buf.split_to(native_buf.len());
1512 let bytes_rest = bytes_buf.split_to(bytes_buf.len());
1513 assert_eq!(native_rest, bytes_rest);
1514 assert_eq!(native_buf, bytes_buf);
1515 assert!(native_buf.is_empty());
1516 assert!(bytes_buf.is_empty());
1517 }
1518
1519 #[test]
1520 #[should_panic(expected = "split_to out of bounds")]
1521 fn test_iobuf_split_to_out_of_bounds() {
1522 let mut buf = IoBuf::from(b"abc");
1523 let _ = buf.split_to(4);
1524 }
1525
1526 #[test]
1527 fn test_iobufmut_core_behaviors() {
1528 let mut buf = IoBufMut::with_capacity(100);
1530 assert!(buf.capacity() >= 100);
1531 assert_eq!(buf.len(), 0);
1532 buf.put_slice(b"hello");
1533 buf.put_slice(b" world");
1534 assert_eq!(buf, b"hello world");
1535 assert_eq!(buf, &b"hello world"[..]);
1536 assert_eq!(buf.freeze(), b"hello world");
1537
1538 let mut zeroed = IoBufMut::zeroed(10);
1540 assert_eq!(zeroed, &[0u8; 10]);
1541 unsafe { zeroed.set_len(5) };
1543 assert_eq!(zeroed, &[0u8; 5]);
1544 zeroed.as_mut()[..5].copy_from_slice(b"hello");
1545 assert_eq!(&zeroed.as_ref()[..5], b"hello");
1546 let frozen = zeroed.freeze();
1547 let vec: Vec<u8> = frozen.into();
1548 assert_eq!(&vec[..5], b"hello");
1549 }
1550
1551 #[test]
1552 fn test_iobufmut_freeze_after_advance_recovers_capacity() {
1553 let mut buf = IoBufMut::with_capacity(16);
1554 assert_eq!(buf.capacity(), 16);
1555 buf.put_slice(b"abcdefghijklmnop");
1556 buf.advance(3);
1557 assert_eq!(buf.as_ref(), b"defghijklmnop");
1558 assert_eq!(buf.capacity(), 13);
1559
1560 let frozen = buf.freeze();
1561 assert_eq!(frozen.as_ref(), b"defghijklmnop");
1562
1563 let recovered = frozen
1564 .try_into_mut()
1565 .expect("unique buffer must recover mutability");
1566 assert_eq!(recovered.as_ref(), b"defghijklmnop");
1567 assert_eq!(recovered.capacity(), 13);
1568 }
1569
1570 #[test]
1571 fn test_iobufmut_buf_trait() {
1572 let mut buf = IoBufMut::from(b"hello world");
1574 assert_eq!(buf.remaining(), 11);
1575 assert_eq!(buf.chunk(), b"hello world");
1576
1577 buf.advance(6);
1578 assert_eq!(buf.remaining(), 5);
1579 assert_eq!(buf.chunk(), b"world");
1580
1581 buf.advance(5);
1582 assert_eq!(buf.remaining(), 0);
1583 assert!(buf.chunk().is_empty());
1584 }
1585
1586 #[test]
1587 #[should_panic(expected = "cannot advance")]
1588 fn test_iobufmut_advance_past_end() {
1589 let mut buf = IoBufMut::from(b"hello");
1590 buf.advance(10);
1591 }
1592
1593 #[test]
1594 fn test_iobufmut_copy_to_slice_tracks_len_and_cap() {
1595 let mut buf = IoBufMut::with_capacity(16);
1599 buf.put_slice(b"abcdefgh");
1600
1601 let mut dst = [0u8; 3];
1602 buf.copy_to_slice(&mut dst);
1603 assert_eq!(&dst, b"abc");
1604 assert_eq!(buf.as_ref(), b"defgh");
1605 assert_eq!(buf.len(), 5);
1606 assert_eq!(buf.capacity(), 13);
1607
1608 let mut dst = [0u8; 2];
1610 buf.try_copy_to_slice(&mut dst).unwrap();
1611 assert_eq!(&dst, b"de");
1612 assert_eq!(buf.capacity(), 11);
1613
1614 let mut dst = [0u8; 4];
1616 let err = buf.try_copy_to_slice(&mut dst).unwrap_err();
1617 assert_eq!(err.requested, 4);
1618 assert_eq!(err.available, 3);
1619 assert_eq!(buf.as_ref(), b"fgh");
1620 assert_eq!(buf.capacity(), 11);
1621
1622 let frozen = buf.freeze();
1626 assert_eq!(frozen.as_ref(), b"fgh");
1627 let recovered = frozen.try_into_mut().expect("unique buffer recovers");
1628 assert_eq!(recovered.as_ref(), b"fgh");
1629 assert_eq!(recovered.capacity(), 11);
1630 }
1631
1632 #[test]
1633 fn test_iobufmut_write_after_partial_advance_appends_at_tail() {
1634 let mut buf = IoBufMut::with_capacity(16);
1638 buf.put_slice(b"hello");
1639 buf.advance(2);
1640 buf.put_slice(b"world");
1641 assert_eq!(buf.as_ref(), b"lloworld");
1642 assert_eq!(buf.len(), 8);
1643 assert_eq!(buf.capacity(), 14);
1644 }
1645
1646 #[test]
1647 #[should_panic(expected = "Not enough bytes remaining in buffer")]
1648 fn test_iobufmut_copy_to_slice_past_end() {
1649 let mut buf = IoBufMut::from(b"ab");
1650 let mut dst = [0u8; 3];
1651 buf.copy_to_slice(&mut dst);
1652 }
1653
1654 #[test]
1655 #[should_panic(expected = "copy_to_bytes out of bounds")]
1656 fn test_iobufmut_copy_to_bytes_past_end() {
1657 let mut buf = IoBufMut::from(b"ab");
1658 let _ = buf.copy_to_bytes(3);
1659 }
1660
1661 #[test]
1662 fn test_iobufmut_put_bytes_success() {
1663 let mut buf = IoBufMut::with_capacity(8);
1664 buf.put_bytes(7, 5);
1665 assert_eq!(buf.as_ref(), &[7u8; 5]);
1666 assert_eq!(buf.len(), 5);
1667 assert_eq!(buf.remaining_mut(), 3);
1668 }
1669
1670 #[test]
1671 fn test_iobufmut_put_multi_chunk_source() {
1672 let mut buf = IoBufMut::with_capacity(8);
1673 buf.put((&b"hel"[..]).chain(&b"lo"[..]));
1674 assert_eq!(buf.as_ref(), b"hello");
1675 assert_eq!(buf.remaining_mut(), 3);
1676 }
1677
1678 #[test]
1679 #[should_panic(expected = "cannot advance past end of buffer")]
1680 fn test_iobufmut_put_slice_past_capacity() {
1681 let mut buf = IoBufMut::with_capacity(4);
1682 buf.put_slice(b"hello");
1683 }
1684
1685 #[test]
1686 #[should_panic(expected = "cannot advance past end of buffer")]
1687 fn test_iobufmut_put_bytes_past_capacity() {
1688 let mut buf = IoBufMut::with_capacity(4);
1689 buf.put_bytes(0, 5);
1690 }
1691
1692 #[test]
1693 #[should_panic(expected = "cannot advance past end of buffer")]
1694 fn test_iobufmut_advance_mut_past_capacity() {
1695 let mut buf = IoBufMut::with_capacity(4);
1696 unsafe { buf.advance_mut(5) };
1699 }
1700
1701 #[test]
1702 #[should_panic(expected = "cannot advance past end of buffer")]
1703 fn test_iobufmut_put_past_capacity() {
1704 let mut buf = IoBufMut::with_capacity(4);
1705 buf.put(&b"hello"[..]);
1706 }
1707
1708 #[test]
1709 fn test_iobuf_additional_conversion_and_trait_paths() {
1710 let mut native_mut = IoBufMut::with_capacity(4);
1711 native_mut.put_slice(b"data");
1712 let native = native_mut.freeze();
1713 assert!(!native.as_ptr().is_null());
1714
1715 let mut adopted_vec = Vec::with_capacity(64);
1718 adopted_vec.extend_from_slice(&[1u8, 2, 3]);
1719 let unique = IoBuf::from(adopted_vec);
1720 let unique_mut = unique.try_into_mut().expect("adopted vec should convert");
1721 assert_eq!(unique_mut.as_ref(), &[1u8, 2, 3]);
1722
1723 let shared = IoBuf::from(vec![4u8, 5, 6]);
1724 let _shared_clone = shared.clone();
1725 assert!(shared.try_into_mut().is_err());
1726
1727 let exact = IoBuf::from(vec![7u8, 8, 9]);
1730 assert_eq!(
1731 exact
1732 .try_into_mut()
1733 .expect("exactly-sized vec must adopt")
1734 .capacity(),
1735 3
1736 );
1737 let external = IoBuf::from(Bytes::from(vec![7u8, 8, 9]));
1738 assert!(external.try_into_mut().is_err());
1739
1740 let expected: &[u8] = &[9u8, 8];
1741 let eq_buf = IoBuf::from(vec![9u8, 8]);
1742 assert!(PartialEq::<[u8]>::eq(&eq_buf, expected));
1743
1744 let static_slice: &'static [u8] = b"static";
1745 assert_eq!(IoBuf::from(static_slice), b"static");
1746
1747 let mut native_mut = IoBufMut::with_capacity(3);
1748 native_mut.put_slice(b"xyz");
1749 let native = native_mut.freeze();
1750 let native_ptr = native.as_ptr();
1751 let vec_out: Vec<u8> = native.clone().into();
1752 let bytes_out: Bytes = native.into();
1753 assert_eq!(vec_out, b"xyz");
1754 assert_eq!(bytes_out.as_ref(), b"xyz");
1755
1756 assert_eq!(bytes_out.as_ptr(), native_ptr);
1758 }
1759
1760 #[test]
1761 fn test_iobuf_from_bytes_zero_copy_round_trip() {
1762 let bytes = Bytes::from(vec![1u8; 64]);
1764 let payload_ptr = bytes.as_ptr();
1765 let buf = IoBuf::from(bytes.clone());
1766 assert_eq!(buf.as_ptr(), payload_ptr);
1767 assert_eq!(buf, bytes.as_ref());
1768
1769 let out: Bytes = buf.into();
1772 assert_eq!(out.as_ptr(), payload_ptr);
1773 assert_eq!(out, bytes);
1774
1775 let sliced = IoBuf::from(bytes).slice(8..32);
1777 let sliced_ptr = sliced.as_ptr();
1778 let sliced_out: Bytes = sliced.into();
1779 assert_eq!(sliced_out.as_ptr(), sliced_ptr);
1780 assert_eq!(sliced_out.len(), 24);
1781 }
1782
1783 #[test]
1784 fn test_iobuf_from_bytes_mut_zero_copy() {
1785 let mut bytes = BytesMut::with_capacity(32);
1786 bytes.extend_from_slice(b"hello");
1787 let payload_ptr = bytes.as_ref().as_ptr();
1788 let buf = IoBuf::from(bytes);
1789 assert_eq!(buf.as_ptr(), payload_ptr);
1790 assert_eq!(buf, b"hello");
1791 }
1792
1793 #[test]
1794 fn test_iobuf_static_into_bytes_uses_from_static() {
1795 let buf = IoBuf::from(b"static-payload");
1796 let payload_ptr = buf.as_ptr();
1797 let bytes: Bytes = buf.into();
1798 assert_eq!(bytes.as_ptr(), payload_ptr);
1799 assert_eq!(bytes.as_ref(), b"static-payload");
1800 }
1801
1802 #[test]
1803 fn test_iobuf_vec_adoption_round_trip_zero_copy() {
1804 let mut vec = Vec::with_capacity(128);
1807 vec.extend_from_slice(b"adopted payload");
1808 let base = vec.as_ptr() as usize;
1809 let buf = IoBuf::from(vec);
1810 assert_eq!(buf.as_ref().as_ptr() as usize, base);
1811
1812 let mut recovered = buf
1813 .try_into_mut()
1814 .expect("adopted vec recovers mutability zero-copy");
1815 assert_eq!(recovered.as_mut_ptr() as usize, base);
1816 assert_eq!(recovered.as_ref(), b"adopted payload");
1817 assert!(recovered.capacity() > recovered.len());
1818 recovered.put_slice(b"!");
1819 assert_eq!(recovered.as_ref(), b"adopted payload!");
1820 }
1821
1822 #[test]
1823 fn test_iobufmut_decode_preserves_byte_fields() {
1824 let values = vec![Bytes::from_static(b"abc"), Bytes::from_static(b"def")];
1825 let source = IoBufMut::from(values.encode());
1826 let range = source.as_ref().as_ptr_range();
1827 let decoded = Vec::<Bytes>::decode_cfg(source, &((..).into(), (..).into())).unwrap();
1828 assert_eq!(decoded, values);
1829 assert!(decoded.iter().all(|field| range.contains(&field.as_ptr())));
1830 }
1831
1832 #[test]
1833 fn test_iobuf_read_cfg_zero_copy_from_iobuf_source() {
1834 let cfg: RangeCfg<usize> = (0..=1024).into();
1838 let mut source = IoBuf::from(IoBuf::from(vec![7u8; 100]).encode());
1839 let prefix = source.len() - 100;
1840 let payload_ptr = source.as_ref()[prefix..].as_ptr();
1841 let decoded = IoBuf::read_cfg(&mut source, &cfg).unwrap();
1842 assert_eq!(decoded.len(), 100);
1843 assert_eq!(decoded.as_ptr(), payload_ptr);
1844 assert_eq!(decoded, [7u8; 100]);
1845
1846 let encoded = IoBuf::from(vec![7u8; 100]).encode();
1848 let mut native = IoBufMut::with_capacity(encoded.len());
1849 native.put_slice(&encoded);
1850 let mut source = native.freeze();
1851 let payload_ptr = source.as_ref()[prefix..].as_ptr();
1852 let decoded = IoBuf::read_cfg(&mut source, &cfg).unwrap();
1853 assert_eq!(decoded.as_ptr(), payload_ptr);
1854
1855 assert!(is_unshared(&decoded));
1858 }
1859
1860 #[test]
1863 fn test_take_owned_other_containers() {
1864 let cfg: RangeCfg<usize> = (0..=1024).into();
1865 let mut source = IoBuf::from(IoBuf::from(vec![7u8; 100]).encode());
1866 let decoded = Bytes::read_cfg(&mut source, &cfg).unwrap();
1867 assert_eq!(decoded, vec![7u8; 100]);
1868
1869 let encoded = IoBuf::from(vec![7u8; 100]).encode();
1870 let mut source = IoBufs::from(IoBuf::copy_from_slice(&encoded[..50]));
1871 source.append(IoBuf::copy_from_slice(&encoded[50..]));
1872 let decoded = IoBuf::read_cfg(&mut source, &cfg).unwrap();
1873 assert_eq!(decoded, [7u8; 100]);
1874 assert!(source.is_empty());
1875 }
1876
1877 #[test]
1878 #[should_panic(expected = "cannot advance")]
1879 fn test_iobufmut_put_does_not_trust_lying_buf() {
1880 struct LyingBuf;
1884 impl bytes::Buf for LyingBuf {
1885 fn remaining(&self) -> usize {
1886 1
1887 }
1888 fn chunk(&self) -> &[u8] {
1889 &[0xAB; 64]
1890 }
1891 fn advance(&mut self, _cnt: usize) {}
1892 }
1893
1894 let mut buf = IoBufMut::with_capacity(8);
1895 buf.put(LyingBuf);
1896 }
1897
1898 #[test]
1899 fn test_handle_auto_traits() {
1900 fn check<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
1901 check::<IoBuf>();
1902 check::<IoBufMut>();
1903 }
1904
1905 #[test]
1906 fn test_unshared_lifecycle_keeps_descriptor() {
1907 let mut buf = IoBufMut::with_capacity(16);
1908 let base = buf.as_mut_ptr();
1909 buf.put_slice(b"0123456789");
1910 let mut frozen = buf.freeze();
1911 assert!(is_unshared(&frozen));
1912
1913 frozen.advance(3);
1916 let mut buf = frozen.try_into_mut().unwrap();
1917 assert_eq!(buf.as_mut_ptr(), unsafe { base.add(3) });
1919 assert_eq!(buf.as_ref(), b"3456789");
1920 assert_eq!(buf.capacity(), 13);
1921 buf.put_slice(b"abcdef");
1922 assert_eq!(buf.capacity(), 13);
1923
1924 let frozen = buf.freeze();
1925 assert!(is_unshared(&frozen));
1926 let mut buf = frozen.try_into_mut().unwrap();
1927 assert_eq!(buf.as_ref(), b"3456789abcdef");
1928 buf.advance(13);
1929 assert_eq!(buf.capacity(), 0);
1930
1931 let mut frozen = IoBufMut::from(&b"xyz"[..]).freeze();
1933 frozen.advance(3);
1934 assert!(frozen.is_empty() && is_unshared(&frozen));
1935 let recovered = frozen.try_into_mut().unwrap();
1936 assert_eq!((recovered.len(), recovered.capacity()), (0, 0));
1937 }
1938
1939 #[test]
1940 fn test_first_share_promotes_once() {
1941 let buf = unshared(8, 12);
1942 let first = buf.clone();
1943 let (addr, refs) = record(&buf).unwrap();
1944 assert_eq!(refs, 2);
1945 assert_eq!(record(&first), Some((addr, 2)));
1946
1947 let second = first.clone();
1949 let third = buf.slice(2..5);
1950 assert_eq!(record(&third), Some((addr, 4)));
1951 assert_eq!(third, [2u8, 3, 4]);
1952 assert_eq!(second, buf);
1953
1954 let buf = buf.try_into_mut().unwrap_err();
1956 drop((first, second, third));
1957 assert_eq!(refcount(&buf), Some(1));
1958 let recovered = buf.try_into_mut().unwrap();
1959 assert_eq!(recovered.as_ref(), [0u8, 1, 2, 3, 4, 5, 6, 7]);
1960 assert_eq!(recovered.capacity(), 12);
1961 }
1962
1963 #[test]
1964 fn test_slice_promotes_from_source_view() {
1965 let mut buf = unshared(100, 128);
1969 buf.advance(5);
1970 let slice = buf.slice(10..30);
1971 assert_eq!(refcount(&slice), Some(2));
1972 drop(buf);
1973 let recovered = slice.try_into_mut().unwrap();
1974 assert_eq!(recovered.as_ref(), (15u8..35).collect::<Vec<_>>());
1975 assert_eq!(recovered.capacity(), 128 - 15);
1976 }
1977
1978 #[test]
1979 fn test_aligned_descriptor_promotes_from_unaligned_view() {
1980 let alignment = NonZeroUsize::new(64).unwrap();
1981 let mut buf = IoBufMut::with_alignment(256, alignment);
1982 assert!((buf.as_mut_ptr() as usize).is_multiple_of(64));
1983 buf.put_bytes(9, 100);
1984
1985 let mut frozen = buf.freeze();
1988 frozen.advance(3);
1989 let view = frozen.clone();
1990 drop(frozen);
1991
1992 let mut recovered = view.try_into_mut().unwrap();
1995 assert_eq!(recovered.capacity(), 253);
1996 recovered.put_bytes(1, 156);
1997 assert_eq!(recovered.len(), 253);
1998 }
1999
2000 #[test]
2001 fn test_clone_of_empty_cursor_keeps_allocation() {
2002 let mut buf = unshared(4, 8);
2003 buf.advance(4);
2004 assert!(buf.is_empty() && is_unshared(&buf));
2005
2006 let clone = buf.clone();
2010 assert_eq!(refcount(&clone), Some(2));
2011 drop(clone);
2012
2013 let recovered = buf.try_into_mut().unwrap();
2014 assert_eq!((recovered.len(), recovered.capacity()), (0, 4));
2015 }
2016
2017 #[test]
2018 fn test_moves_and_empty_views_do_not_promote() {
2019 let mut buf = unshared(8, 8);
2020 let mut moved = std::mem::take(&mut buf);
2021 assert!(is_unshared(&moved));
2022 assert!(buf.is_empty() && !is_native(&buf));
2023
2024 assert!(moved.split_to(0).is_empty());
2026 assert!(moved.slice(3..3).is_empty());
2027 assert!(is_unshared(&moved));
2028
2029 let mut whole = moved.split_to(8);
2031 assert!(moved.is_empty() && is_unshared(&whole));
2032 let mut taken: IoBuf = whole.take_owned(8);
2033 assert!(is_unshared(&taken));
2034 let bytes = taken.copy_to_bytes(8);
2035 assert_eq!(bytes, [0u8, 1, 2, 3, 4, 5, 6, 7].as_slice());
2036 }
2037
2038 #[test]
2039 fn test_partial_split_promotes_and_shares() {
2040 let mut buf = unshared(10, 16);
2043 let prefix = buf.split_to(4);
2044 let (addr, refs) = record(&buf).unwrap();
2045 assert_eq!(refs, 2);
2046 assert_eq!(record(&prefix), Some((addr, 2)));
2047 assert_eq!(prefix, [0u8, 1, 2, 3]);
2048
2049 let middle = buf.split_to(2);
2051 let taken: IoBuf = buf.take_owned(1);
2052 assert_eq!(record(&taken), Some((addr, 4)));
2053 assert_eq!(
2054 (middle, taken),
2055 (IoBuf::from(&[4u8, 5]), IoBuf::from(&[6u8]))
2056 );
2057 assert_eq!(buf, [7u8, 8, 9]);
2058
2059 drop(prefix);
2061 let recovered = buf.try_into_mut().unwrap();
2062 assert_eq!(recovered.capacity(), 9);
2063 }
2064
2065 #[test]
2066 fn test_bytes_from_unshared_view_keeps_allocation() {
2067 let mut buf = unshared(10, 16);
2071 buf.advance(2);
2072 let bytes = Bytes::from(buf);
2073 let slice = bytes.slice(1..4);
2074 drop(bytes);
2075 std::thread::spawn(move || assert_eq!(slice, [3u8, 4, 5].as_slice()))
2076 .join()
2077 .unwrap();
2078
2079 let direct = Bytes::from_owner(unshared(3, 5));
2081 let round_trip = IoBuf::from(direct.clone());
2082 assert_eq!(round_trip, [0u8, 1, 2]);
2083 drop(direct);
2084 assert_eq!(round_trip, [0u8, 1, 2]);
2085
2086 let mut buf = unshared(10, 16);
2088 let drained = buf.copy_to_bytes(4);
2089 assert_eq!(refcount(&buf), Some(2));
2090 drop(drained);
2091 assert_eq!(refcount(&buf), Some(1));
2092 assert_eq!(buf.try_into_mut().unwrap().capacity(), 12);
2093 }
2094
2095 #[test]
2096 fn test_freeze_tail_overflow_allocates_record() {
2097 let capacity = (1 << 17) + 1;
2100 let mut buf = IoBufMut::with_capacity(capacity);
2101 let base = buf.as_mut_ptr();
2102 buf.put_u8(1);
2103 let frozen = buf.freeze();
2104 let (addr, refs) = record(&frozen).unwrap();
2105 assert_eq!(refs, 1);
2106 let view = frozen.clone();
2107 assert_eq!(record(&view), Some((addr, 2)));
2108 drop(view);
2109 let mut recovered = frozen.try_into_mut().unwrap();
2110 assert_eq!(recovered.as_mut_ptr(), base);
2111 assert_eq!(recovered.capacity(), capacity);
2112 }
2113
2114 #[test]
2115 fn test_concurrent_first_clones_share_one_record() {
2116 let buf = unshared(32, 32);
2119 let views: Vec<IoBuf> = std::thread::scope(|scope| {
2120 let buf = &buf;
2121 let handles: Vec<_> = (0..4)
2122 .map(|i| {
2123 scope.spawn(move || {
2124 if i % 2 == 0 {
2125 buf.clone()
2126 } else {
2127 buf.slice(1..31)
2128 }
2129 })
2130 })
2131 .collect();
2132 handles.into_iter().map(|h| h.join().unwrap()).collect()
2133 });
2134
2135 let (addr, refs) = record(&buf).unwrap();
2137 assert_eq!(refs, 5);
2138 assert!(views.iter().all(|view| record(view).unwrap().0 == addr));
2139
2140 drop(views);
2142 assert_eq!(buf.try_into_mut().unwrap().capacity(), 32);
2143 }
2144
2145 #[test]
2146 fn test_iobufmut_from_iobuf() {
2147 let mut unique = IoBufMut::with_capacity(4);
2149 unique.put_slice(b"data");
2150 let unique_ptr = unique.as_mut_ptr();
2151 let mut recovered = IoBufMut::from(unique.freeze());
2152 assert_eq!(recovered.as_ref(), b"data");
2153 assert_eq!(recovered.as_mut_ptr(), unique_ptr);
2154
2155 let mut shared = IoBufMut::with_capacity(4);
2157 shared.put_slice(b"copy");
2158 let shared = shared.freeze();
2159 let shared_ptr = shared.as_ptr();
2160 let _clone = shared.clone();
2161 let mut copied = IoBufMut::from(shared);
2162 assert_eq!(copied.as_ref(), b"copy");
2163 assert_ne!(copied.as_mut_ptr() as *const u8, shared_ptr);
2164
2165 let mut mirror = IoBufMut::with_capacity(8);
2168 mirror.put_slice(b"abcdefgh");
2169 let mirror_cap = mirror.capacity();
2170 let mirror_ptr = mirror.as_mut_ptr();
2171 let frozen = mirror.freeze();
2172 let head = frozen.slice(0..3);
2173 let tail = frozen.slice(5..8);
2174 drop(head);
2175 drop(tail);
2176 let mut recovered = IoBufMut::from(frozen);
2177 assert_eq!(recovered.as_ref(), b"abcdefgh");
2178 assert_eq!(recovered.as_mut_ptr(), mirror_ptr);
2179 assert_eq!(recovered.capacity(), mirror_cap);
2180 }
2181
2182 #[test]
2183 fn test_iobufmut_additional_conversion_and_trait_paths() {
2184 let mut buf = IoBufMut::from([1u8, 2, 3, 4]);
2186 assert!(!buf.is_empty());
2187 buf.truncate(2);
2188 assert_eq!(buf.as_ref(), &[1u8, 2]);
2189 buf.clear();
2190 assert!(buf.is_empty());
2191 buf.put_slice(b"xyz");
2192
2193 let expected: &[u8] = b"xyz";
2195 assert!(PartialEq::<[u8]>::eq(&buf, expected));
2196 assert!(buf == b"xyz"[..]);
2197 assert!(buf == *b"xyz");
2198 assert!(buf == b"xyz");
2199
2200 let from_array = IoBufMut::from([7u8, 8]);
2202 assert_eq!(from_array.as_ref(), &[7u8, 8]);
2203
2204 let from_bytesmut = IoBufMut::from(BytesMut::from(&b"hi"[..]));
2205 assert_eq!(from_bytesmut.as_ref(), b"hi");
2206
2207 let from_bytes = IoBufMut::from(Bytes::from_static(b"ok"));
2208 assert_eq!(from_bytes.as_ref(), b"ok");
2209
2210 let from_iobuf = IoBufMut::from(IoBuf::from(Bytes::from_static(b"io")));
2212 assert_eq!(from_iobuf.as_ref(), b"io");
2213 }
2214
2215 #[test]
2216 fn test_iobufmut_from_bytesmut_preserves_capacity() {
2217 let mut bytes = BytesMut::with_capacity(100);
2219 bytes.put_slice(b"abc");
2220 let cap = bytes.capacity();
2221 let base = bytes.as_ptr() as usize;
2222 let buf = IoBufMut::from(bytes);
2223 assert_eq!(buf.as_ref(), b"abc");
2224 assert_eq!(buf.capacity(), cap);
2225 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2226
2227 let mut advanced = BytesMut::with_capacity(100);
2230 advanced.put_slice(b"prefix-payload");
2231 let base = advanced.as_ptr() as usize;
2232 advanced.advance(7);
2233 let buf = IoBufMut::from(advanced);
2234 assert_eq!(buf.as_ref(), b"payload");
2235 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2236 assert!(buf.capacity() >= 100);
2237
2238 let bytes = BytesMut::with_capacity(64);
2240 let cap = bytes.capacity();
2241 let mut buf = IoBufMut::from(bytes);
2242 assert!(buf.is_empty());
2243 assert_eq!(buf.capacity(), cap);
2244 buf.put_bytes(7, cap);
2245 assert_eq!(buf.len(), cap);
2246
2247 let mut shared = BytesMut::with_capacity(100);
2250 shared.put_slice(b"shared");
2251 let other = shared.split_to(3);
2252 let cap = shared.capacity();
2253 let base = shared.as_ptr() as usize;
2254 let buf = IoBufMut::from(shared);
2255 assert_eq!(buf.as_ref(), b"red");
2256 assert_ne!(buf.as_ref().as_ptr() as usize, base);
2257 assert_eq!(buf.capacity(), cap);
2258 assert_eq!(other.as_ref(), b"sha");
2259 }
2260
2261 #[test]
2265 fn test_iobufmut_from_bytes_reuses_unique_allocation() {
2266 let mut vec = Vec::with_capacity(100);
2269 vec.extend_from_slice(b"abc");
2270 let base = vec.as_ptr() as usize;
2271 let buf = IoBufMut::from(Bytes::from(vec));
2272 assert_eq!(buf.as_ref(), b"abc");
2273 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2274 assert_eq!(buf.capacity(), 100);
2275
2276 let vec = b"exact".to_vec();
2279 let base = vec.as_ptr() as usize;
2280 let buf = IoBufMut::from(Bytes::from(vec));
2281 assert_eq!(buf.as_ref(), b"exact");
2282 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2283 assert_eq!(buf.capacity(), 5);
2284
2285 let vec = b"prefix-payload".to_vec();
2288 let base = vec.as_ptr() as usize;
2289 let mut advanced = Bytes::from(vec);
2290 advanced.advance(7);
2291 let buf = IoBufMut::from(advanced);
2292 assert_eq!(buf.as_ref(), b"payload");
2293 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2294 assert_eq!(buf.capacity(), 14);
2295
2296 let vec = b"head-tail".to_vec();
2298 let base = vec.as_ptr() as usize;
2299 let whole = Bytes::from(vec);
2300 let tail = whole.slice(5..);
2301 drop(whole);
2302 let buf = IoBufMut::from(tail);
2303 assert_eq!(buf.as_ref(), b"tail");
2304 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2305 assert_eq!(buf.capacity(), 9);
2306
2307 let vec = Vec::<u8>::with_capacity(64);
2309 let base = vec.as_ptr() as usize;
2310 let mut buf = IoBufMut::from(Bytes::from(vec));
2311 assert!(buf.is_empty());
2312 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2313 assert_eq!(buf.capacity(), 64);
2314 buf.put_slice(b"ready");
2315 assert_eq!(buf.as_ref(), b"ready");
2316 assert_eq!(IoBufMut::from(Bytes::new()).capacity(), 0);
2317
2318 let shared = Bytes::from(b"shared".to_vec());
2321 let base = shared.as_ptr() as usize;
2322 let other = shared.clone();
2323 let mut buf = IoBufMut::from(shared);
2324 assert_eq!(buf.as_ref(), b"shared");
2325 assert_ne!(buf.as_ref().as_ptr() as usize, base);
2326 assert_eq!(buf.capacity(), 6);
2327 buf.as_mut()[0] = b'S';
2328 assert_eq!(other.as_ref(), b"shared");
2329
2330 let buf = IoBufMut::from(Bytes::from_static(b"static"));
2333 assert_eq!(buf.as_ref(), b"static");
2334 assert_ne!(buf.as_ref().as_ptr() as usize, b"static".as_ptr() as usize);
2335 let owned = Bytes::from_owner(b"owned".to_vec());
2336 let base = owned.as_ptr() as usize;
2337 let buf = IoBufMut::from(owned);
2338 assert_eq!(buf.as_ref(), b"owned");
2339 assert_ne!(buf.as_ref().as_ptr() as usize, base);
2340 }
2341
2342 #[test]
2343 fn test_iobufmut_from_vec_preserves_capacity() {
2344 let mut vec = Vec::with_capacity(100);
2345 vec.extend_from_slice(b"abc");
2346 let base = vec.as_ptr() as usize;
2347 let buf = IoBufMut::from(vec);
2348 assert_eq!(buf.as_ref(), b"abc");
2349 assert_eq!(buf.capacity(), 100);
2350
2351 assert_eq!(buf.as_ref().as_ptr() as usize, base);
2353
2354 let mut buf = IoBufMut::from(Vec::with_capacity(64));
2357 assert!(buf.is_empty());
2358 assert_eq!(buf.capacity(), 64);
2359 buf.put_bytes(7, 64);
2360 assert_eq!(buf.len(), 64);
2361
2362 assert!(IoBufMut::from(Vec::new()).is_empty());
2365 let exact = IoBufMut::from(vec![1u8, 2, 3]);
2366 assert_eq!(exact.capacity(), 3);
2367 assert_eq!(
2368 exact
2369 .freeze()
2370 .try_into_mut()
2371 .expect("unique view must recover mutability")
2372 .as_ref(),
2373 &[1u8, 2, 3]
2374 );
2375 }
2376
2377 #[test]
2378 #[should_panic(expected = "size must fit a layout")]
2379 fn test_iobufmut_with_capacity_rejects_oversized_request() {
2380 let _ = IoBufMut::with_capacity(isize::MAX as usize + 1);
2383 }
2384
2385 #[test]
2386 fn test_iobufmut_try_with_alignment_declines_impossible_layouts() {
2387 let page = NonZeroUsize::new(4096).expect("non-zero alignment");
2390 assert!(IoBufMut::try_with_alignment(isize::MAX as usize + 1, page).is_none());
2391 assert!(IoBufMut::try_with_alignment(isize::MAX as usize - 4094, page).is_none());
2392 assert!(
2393 IoBufMut::try_with_alignment(64, NonZeroUsize::new(3).expect("non-zero")).is_none()
2394 );
2395 let mut buf =
2396 IoBufMut::try_with_alignment(100, page).expect("a page-aligned 100-byte layout");
2397 assert_eq!(buf.capacity(), 100);
2398 assert!((buf.as_mut_ptr() as usize).is_multiple_of(4096));
2399 assert_eq!(
2400 IoBufMut::try_with_alignment(0, page)
2401 .expect("empty")
2402 .capacity(),
2403 0
2404 );
2405 }
2406
2407 #[test]
2408 fn test_iobuf_aligned_public_paths() {
2409 static ARRAY: &[u8; 4] = b"wxyz";
2413
2414 let alignment = NonZeroUsize::new(64).expect("non-zero alignment");
2415
2416 let mut aligned_mut = IoBufMut::with_alignment(8, alignment);
2418 assert!(aligned_mut.is_empty());
2419 assert_eq!(aligned_mut.capacity(), 8);
2420 assert!((aligned_mut.as_mut_ptr() as usize).is_multiple_of(64));
2421
2422 aligned_mut.put_slice(b"abcdefgh");
2423 assert_eq!(aligned_mut.as_mut(), b"abcdefgh");
2424 assert_eq!(aligned_mut.chunk(), b"abcdefgh");
2425 aligned_mut.advance(2);
2426 assert_eq!(aligned_mut.chunk(), b"cdefgh");
2427
2428 let partial = aligned_mut.copy_to_bytes(2);
2429 assert_eq!(partial.as_ref(), b"cd");
2430 assert_eq!(aligned_mut.as_ref(), b"efgh");
2431 let empty = aligned_mut.copy_to_bytes(0);
2432 assert!(empty.is_empty());
2433 assert_eq!(aligned_mut.as_ref(), b"efgh");
2434
2435 aligned_mut.clear();
2436 assert!(aligned_mut.is_empty());
2437 aligned_mut.put_slice(ARRAY);
2438 assert!(aligned_mut == ARRAY);
2439
2440 let mut fully_drained = IoBufMut::with_alignment(4, alignment);
2442 fully_drained.put_slice(b"lmno");
2443 let empty = fully_drained.copy_to_bytes(0);
2444 assert!(empty.is_empty());
2445 assert_eq!(fully_drained.as_ref(), b"lmno");
2446 let drained = fully_drained.copy_to_bytes(4);
2447 assert_eq!(drained.as_ref(), b"lmno");
2448 assert!(fully_drained.is_empty());
2449
2450 let aligned = aligned_mut.freeze();
2452 assert_eq!(aligned.as_ref(), &ARRAY[..]);
2453 assert!(aligned == ARRAY);
2454 assert!(!aligned.as_ptr().is_null());
2455 assert_eq!(aligned.slice(..2), b"wx");
2456 assert_eq!(aligned.slice(1..), b"xyz");
2457 assert_eq!(aligned.slice(1..=2), b"xy");
2458 assert_eq!(aligned.chunk(), b"wxyz");
2459
2460 let mut split = aligned.clone();
2461 let prefix = split.split_to(2);
2462 assert_eq!(prefix, b"wx");
2463 assert_eq!(split, b"yz");
2464
2465 let mut advanced = aligned.clone();
2466 advanced.advance(2);
2467 assert_eq!(advanced.chunk(), b"yz");
2468
2469 let mut drained = aligned.clone();
2471 let empty = drained.copy_to_bytes(0);
2472 assert!(empty.is_empty());
2473 assert_eq!(drained.as_ref(), &ARRAY[..]);
2474 let first = drained.copy_to_bytes(1);
2475 assert_eq!(first.as_ref(), b"w");
2476 let rest = drained.copy_to_bytes(3);
2477 assert_eq!(rest.as_ref(), b"xyz");
2478 assert_eq!(drained.remaining(), 0);
2479
2480 let mut unique_source = IoBufMut::zeroed_with_alignment(4, alignment);
2482 unique_source.as_mut().copy_from_slice(b"pqrs");
2483 let unique = unique_source.freeze();
2484 let recovered = unique
2485 .try_into_mut()
2486 .expect("unique aligned iobuf should recover mutability");
2487 assert_eq!(recovered.as_ref(), b"pqrs");
2488
2489 let mut shared_source = IoBufMut::zeroed_with_alignment(4, alignment);
2491 shared_source.as_mut().copy_from_slice(b"tuvw");
2492 let shared = shared_source.freeze();
2493 let _shared_clone = shared.clone();
2494 assert!(shared.try_into_mut().is_err());
2495
2496 let vec_out: Vec<u8> = aligned.clone().into();
2498 let bytes_out: Bytes = aligned.into();
2499 assert_eq!(vec_out, ARRAY.to_vec());
2500 assert_eq!(bytes_out.as_ref(), &ARRAY[..]);
2501
2502 let from_array = IoBuf::from(ARRAY);
2503 assert_eq!(from_array, b"wxyz");
2504
2505 let iobufs = IoBufs::from(ARRAY);
2506 assert_eq!(iobufs.chunk(), b"wxyz");
2507 }
2508
2509 #[test]
2510 fn test_iobufmut_aligned_zero_length_constructors() {
2511 let alignment = NonZeroUsize::new(64).expect("non-zero alignment");
2512
2513 let with_alignment = IoBufMut::with_alignment(0, alignment);
2514 assert!(with_alignment.is_empty());
2515 assert_eq!(with_alignment.len(), 0);
2516 assert_eq!(with_alignment.capacity(), 0);
2517
2518 let zeroed = IoBufMut::zeroed_with_alignment(0, alignment);
2519 assert!(zeroed.is_empty());
2520 assert_eq!(zeroed.len(), 0);
2521 assert_eq!(zeroed.capacity(), 0);
2522
2523 let invalid_alignment = NonZeroUsize::new(3).expect("non-zero alignment");
2525 assert_eq!(IoBufMut::with_alignment(0, invalid_alignment).capacity(), 0);
2526 assert_eq!(
2527 IoBufMut::zeroed_with_alignment(0, invalid_alignment).capacity(),
2528 0
2529 );
2530 }
2531
2532 #[test]
2533 fn test_iobufmut_aligned_capacity_stable_across_recovery() {
2534 let alignment = NonZeroUsize::new(4096).expect("non-zero alignment");
2537 let mut buf = IoBufMut::with_alignment(100, alignment);
2538 assert_eq!(buf.capacity(), 100);
2539 assert!((buf.as_mut_ptr() as usize).is_multiple_of(4096));
2540
2541 buf.put_slice(b"data");
2542 let recovered = buf
2543 .freeze()
2544 .try_into_mut()
2545 .expect("unique native view recovers");
2546 assert_eq!(recovered.capacity(), 100);
2547
2548 let zeroed = IoBufMut::zeroed_with_alignment(100, alignment);
2550 assert_eq!(zeroed.len(), 100);
2551 assert_eq!(zeroed.capacity(), 100);
2552 }
2553
2554 #[test]
2555 #[should_panic(expected = "set_len(9) exceeds capacity(8)")]
2556 fn test_iobufmut_set_len_overflow() {
2557 let mut buf = IoBufMut::with_capacity(8);
2558 unsafe { buf.set_len(9) };
2560 }
2561}
2562
2563#[cfg(all(test, not(feature = "loom"), feature = "arbitrary"))]
2566mod tests {
2567 mod conformance {
2568 use super::super::IoBuf;
2569 use commonware_codec::conformance::CodecConformance;
2570
2571 commonware_conformance::conformance_tests! {
2572 CodecConformance<IoBuf>
2573 }
2574 }
2575}