1use std::marker::PhantomData;
44use zerocopy::FromBytes;
45
46#[derive(Debug, Copy, Clone)]
48pub struct PtrByteSlice<'a> {
49 slice: *const [u8],
50 _marker: PhantomData<&'a [u8]>,
51}
52
53impl<'a> PtrByteSlice<'a> {
54 pub unsafe fn new(slice: *const [u8]) -> Self {
60 Self { slice, _marker: PhantomData }
61 }
62
63 pub fn len(&self) -> usize {
65 self.slice.len()
66 }
67
68 pub fn is_empty(&self) -> bool {
70 self.len() == 0
71 }
72
73 pub fn read<T: Copy + FromBytes>(&self) -> Option<T> {
77 let size = std::mem::size_of::<T>();
78 if size > self.len() {
79 return None;
80 }
81 let ptr = self.slice as *const T;
82 unsafe { Some(std::ptr::read_unaligned(ptr)) }
86 }
87
88 pub fn copy_to_slice(&self, dest: &mut [u8]) {
94 assert!(dest.len() >= self.len());
95 unsafe {
101 std::ptr::copy_nonoverlapping(self.slice as *const u8, dest.as_mut_ptr(), self.len());
102 }
103 }
104
105 pub fn subslice(&self, range: std::ops::Range<usize>) -> Self {
111 assert!(range.start <= range.end);
112 assert!(range.end <= self.len());
113 unsafe {
118 let new_ptr = (self.slice as *const u8).add(range.start);
119 let new_slice = std::ptr::slice_from_raw_parts(new_ptr, range.end - range.start);
120 Self::new(new_slice)
121 }
122 }
123
124 pub fn split_at(self, mid: usize) -> (Self, Self) {
130 assert!(mid <= self.len());
131 unsafe {
136 let ptr = self.slice as *const u8;
137 (
138 Self::new(std::ptr::slice_from_raw_parts(ptr, mid)),
139 Self::new(std::ptr::slice_from_raw_parts(ptr.add(mid), self.len() - mid)),
140 )
141 }
142 }
143
144 pub fn as_raw_slice_ptr(&self) -> *const [u8] {
146 self.slice
147 }
148
149 pub fn as_ptr(&self) -> *const u8 {
151 self.slice as *const u8
152 }
153
154 pub fn to_vec(&self) -> Vec<u8> {
157 let mut vec = Vec::with_capacity(self.len());
158 unsafe {
161 std::ptr::copy_nonoverlapping(self.slice as *const u8, vec.as_mut_ptr(), self.len());
162 vec.set_len(self.len());
163 }
164 vec
165 }
166
167 pub fn append_to(&self, vec: &mut Vec<u8>) {
170 let old_len = vec.len();
171 let new_len = old_len + self.len();
172 vec.reserve(self.len());
173 unsafe {
180 let dest_ptr = vec.as_mut_ptr().add(old_len);
181 std::ptr::copy_nonoverlapping(self.slice as *const u8, dest_ptr, self.len());
182 vec.set_len(new_len);
183 }
184 }
185
186 pub fn iter_as<T: Copy + FromBytes>(&self) -> IterAs<'_, T> {
193 let size = std::mem::size_of::<T>();
194 let align = std::mem::align_of::<T>();
195 assert!(size > 0, "Chunk size must be greater than 0");
196 assert_eq!(self.slice as *const u8 as usize % align, 0, "Slice is not aligned to T");
197 assert_eq!(self.len() % size, 0, "Slice length is not a multiple of T size");
198
199 let end = unsafe { (self.slice as *const T).add(self.len() / size) };
204 IterAs { ptr: self.slice as *const T, end, _marker: PhantomData }
205 }
206
207 pub fn chunks(&self, chunk_size: usize) -> Chunks<'_> {
213 assert!(chunk_size > 0, "chunk_size must be > 0");
214 Chunks { slice: *self, chunk_size, offset: 0 }
215 }
216}
217
218#[derive(Debug)]
220pub struct MutPtrByteSlice<'a> {
221 slice: *mut [u8],
222 _marker: PhantomData<&'a mut [u8]>,
223}
224
225impl<'a> MutPtrByteSlice<'a> {
226 pub unsafe fn new(slice: *mut [u8]) -> Self {
232 Self { slice, _marker: PhantomData }
233 }
234
235 pub fn len(&self) -> usize {
237 self.slice.len()
238 }
239
240 pub fn is_empty(&self) -> bool {
242 self.len() == 0
243 }
244
245 pub fn read<T: Copy + FromBytes>(&self) -> Option<T> {
249 let size = std::mem::size_of::<T>();
250 if size > self.len() {
251 return None;
252 }
253 let ptr = self.slice as *const T;
254 unsafe { Some(std::ptr::read_unaligned(ptr)) }
258 }
259
260 pub fn write<T: Copy + FromBytes>(&mut self, val: T) -> Option<()> {
264 let size = std::mem::size_of::<T>();
265 if size > self.len() {
266 return None;
267 }
268 let ptr = self.slice as *mut T;
269 unsafe {
273 std::ptr::write_unaligned(ptr, val);
274 }
275 Some(())
276 }
277
278 pub fn copy_to_slice(&self, dest: &mut [u8]) {
284 assert!(dest.len() >= self.len());
285 unsafe {
291 std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest.as_mut_ptr(), self.len());
292 }
293 }
294
295 pub fn copy_from_ptr_slice(&mut self, src: PtrByteSlice<'_>) {
301 assert_eq!(self.len(), src.len());
302 unsafe {
308 std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
309 }
310 }
311
312 pub fn copy_from_slice(&mut self, src: &[u8]) {
318 assert_eq!(self.len(), src.len());
319 unsafe {
324 std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
325 }
326 }
327
328 pub fn zero_no_rfo(&mut self) {
340 #[cfg(target_arch = "aarch64")]
341 {
342 const CACHE_LINE_SIZE: usize = 64;
343 let addr = self.slice as *mut u8 as usize;
344 let end = addr + self.len();
345
346 let aligned_start = addr.next_multiple_of(CACHE_LINE_SIZE);
347 let aligned_end = end - end % CACHE_LINE_SIZE;
348
349 if aligned_start < aligned_end {
350 let mut p = aligned_start;
351 while p < aligned_end {
352 unsafe {
354 core::arch::asm!(
355 "dc zva, {0}",
356 in(reg) p,
357 options(nostack, preserves_flags),
358 );
359 }
360 p += CACHE_LINE_SIZE;
361 }
362 }
363 }
364 }
365
366 pub fn fill(&mut self, val: u8) {
368 unsafe {
370 std::ptr::write_bytes(self.slice as *mut u8, val, self.len());
371 }
372 }
373
374 pub fn as_ptr_slice(&self) -> PtrByteSlice<'_> {
376 unsafe { PtrByteSlice::new(self.slice as *const [u8]) }
378 }
379
380 pub fn subslice_mut(&mut self, range: std::ops::Range<usize>) -> Self {
386 assert!(range.start <= range.end);
387 assert!(range.end <= self.len());
388 unsafe {
393 let new_ptr = (self.slice as *mut u8).add(range.start);
394 let new_slice = std::ptr::slice_from_raw_parts_mut(new_ptr, range.end - range.start);
395 Self::new(new_slice)
396 }
397 }
398
399 pub fn split_at_mut(self, mid: usize) -> (Self, Self) {
405 assert!(mid <= self.len());
406 unsafe {
412 let ptr = self.slice as *mut u8;
413 (
414 Self::new(std::ptr::slice_from_raw_parts_mut(ptr, mid)),
415 Self::new(std::ptr::slice_from_raw_parts_mut(ptr.add(mid), self.len() - mid)),
416 )
417 }
418 }
419
420 pub fn as_raw_mut_slice_ptr(&self) -> *mut [u8] {
422 self.slice
423 }
424
425 pub fn as_ptr(&self) -> *const u8 {
427 self.slice as *const u8
428 }
429
430 pub fn as_mut_ptr(&self) -> *mut u8 {
432 self.slice as *mut u8
433 }
434
435 pub fn reborrow(&mut self) -> MutPtrByteSlice<'_> {
437 MutPtrByteSlice { slice: self.slice, _marker: std::marker::PhantomData }
438 }
439
440 pub fn to_vec(&self) -> Vec<u8> {
443 let mut vec = Vec::with_capacity(self.len());
444 unsafe {
447 std::ptr::copy_nonoverlapping(self.slice as *mut u8, vec.as_mut_ptr(), self.len());
448 vec.set_len(self.len());
449 }
450 vec
451 }
452
453 pub fn append_to(&self, vec: &mut Vec<u8>) {
456 let old_len = vec.len();
457 let new_len = old_len + self.len();
458 vec.reserve(self.len());
459 unsafe {
466 let dest_ptr = vec.as_mut_ptr().add(old_len);
467 std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest_ptr, self.len());
468 vec.set_len(new_len);
469 }
470 }
471
472 pub fn iter_as_mut<T: Copy + FromBytes>(&mut self) -> IterAsMut<'_, T> {
479 let size = std::mem::size_of::<T>();
480 let align = std::mem::align_of::<T>();
481 assert!(size > 0, "Chunk size must be greater than 0");
482 assert_eq!(self.slice as *mut u8 as usize % align, 0, "Slice is not aligned to T");
483 assert_eq!(self.len() % size, 0, "Slice length is not a multiple of T size");
484
485 let end = unsafe { (self.slice as *mut T).add(self.len() / size) };
490 IterAsMut { ptr: self.slice as *mut T, end, _marker: PhantomData }
491 }
492
493 pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_> {
499 assert!(chunk_size > 0, "chunk_size must be > 0");
500 ChunksMut { slice: self.reborrow(), chunk_size, offset: 0 }
501 }
502
503 pub fn writer(self) -> Writer<'a> {
505 Writer::new(self)
506 }
507}
508
509#[derive(Debug)]
511pub struct Writer<'a> {
512 slice: MutPtrByteSlice<'a>,
513 pos: usize,
514}
515
516impl<'a> Writer<'a> {
517 pub fn new(slice: MutPtrByteSlice<'a>) -> Self {
519 Self { slice, pos: 0 }
520 }
521
522 pub fn position(&self) -> usize {
524 self.pos
525 }
526
527 pub fn remaining(&mut self) -> MutPtrByteSlice<'_> {
529 let len = self.slice.len();
530 self.slice.reborrow().subslice_mut(self.pos..len)
531 }
532
533 pub fn into_written(mut self) -> MutPtrByteSlice<'a> {
535 let pos = self.pos;
536 self.slice.subslice_mut(0..pos)
537 }
538}
539
540impl std::io::Write for Writer<'_> {
541 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
542 let remaining = self.slice.len() - self.pos;
543 if remaining == 0 {
544 return Ok(0);
545 }
546 let to_write = std::cmp::min(remaining, buf.len());
547 self.slice
548 .reborrow()
549 .subslice_mut(self.pos..self.pos + to_write)
550 .copy_from_slice(&buf[..to_write]);
551 self.pos += to_write;
552 Ok(to_write)
553 }
554
555 fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
556 if buf.len() > self.slice.len() - self.pos {
557 return Err(std::io::Error::new(
558 std::io::ErrorKind::WriteZero,
559 "failed to write whole buffer",
560 ));
561 }
562 self.slice.reborrow().subslice_mut(self.pos..self.pos + buf.len()).copy_from_slice(buf);
563 self.pos += buf.len();
564 Ok(())
565 }
566
567 fn flush(&mut self) -> std::io::Result<()> {
568 Ok(())
569 }
570}
571
572unsafe impl Send for PtrByteSlice<'_> {}
577unsafe impl Sync for PtrByteSlice<'_> {}
579unsafe impl Send for MutPtrByteSlice<'_> {}
585unsafe impl Sync for MutPtrByteSlice<'_> {}
588
589impl<'a> From<&'a [u8]> for PtrByteSlice<'a> {
590 fn from(slice: &'a [u8]) -> Self {
591 unsafe { Self::new(slice as *const [u8]) }
593 }
594}
595
596impl<'a> From<&'a Vec<u8>> for PtrByteSlice<'a> {
597 fn from(vec: &'a Vec<u8>) -> Self {
598 Self::from(vec.as_slice())
599 }
600}
601
602impl<'a> From<MutPtrByteSlice<'a>> for PtrByteSlice<'a> {
603 fn from(slice: MutPtrByteSlice<'a>) -> Self {
604 unsafe { Self::new(slice.slice as *const [u8]) }
608 }
609}
610
611impl<'a> From<&'a mut [u8]> for MutPtrByteSlice<'a> {
612 fn from(slice: &'a mut [u8]) -> Self {
613 unsafe { Self::new(slice as *mut [u8]) }
615 }
616}
617
618impl<'a> From<&'a mut Vec<u8>> for MutPtrByteSlice<'a> {
619 fn from(vec: &'a mut Vec<u8>) -> Self {
620 Self::from(vec.as_mut_slice())
621 }
622}
623
624pub struct IterAs<'a, T> {
626 ptr: *const T,
627 end: *const T,
628 _marker: PhantomData<&'a T>,
629}
630
631impl<'a, T: Copy + FromBytes> Iterator for IterAs<'a, T> {
632 type Item = Elem<'a, T>;
633
634 fn next(&mut self) -> Option<Self::Item> {
635 if self.ptr == self.end {
636 None
637 } else {
638 let current = self.ptr;
639 self.ptr = unsafe { self.ptr.add(1) };
642 Some(Elem { ptr: current, _marker: PhantomData })
643 }
644 }
645}
646
647pub struct Elem<'a, T> {
649 ptr: *const T,
650 _marker: PhantomData<&'a T>,
651}
652
653impl<T: Copy + FromBytes> Elem<'_, T> {
654 pub fn read(&self) -> T {
659 unsafe { std::ptr::read(self.ptr) }
661 }
662}
663
664pub struct IterAsMut<'a, T> {
666 ptr: *mut T,
667 end: *mut T,
668 _marker: PhantomData<&'a mut T>,
669}
670
671impl<'a, T: Copy + FromBytes> Iterator for IterAsMut<'a, T> {
672 type Item = ElemMut<'a, T>;
673
674 fn next(&mut self) -> Option<Self::Item> {
675 if self.ptr == self.end {
676 None
677 } else {
678 let current = self.ptr;
679 self.ptr = unsafe { self.ptr.add(1) };
682 Some(ElemMut { ptr: current, _marker: PhantomData })
683 }
684 }
685}
686
687pub struct ElemMut<'a, T> {
689 ptr: *mut T,
690 _marker: PhantomData<&'a mut T>,
691}
692
693impl<T: Copy + FromBytes> ElemMut<'_, T> {
694 pub fn read(&self) -> T {
699 unsafe { std::ptr::read(self.ptr) }
701 }
702
703 pub fn write(&self, val: T) {
708 unsafe { std::ptr::write(self.ptr, val) }
710 }
711}
712
713pub struct Chunks<'a> {
715 slice: PtrByteSlice<'a>,
716 chunk_size: usize,
717 offset: usize,
718}
719
720impl<'a> Iterator for Chunks<'a> {
721 type Item = PtrByteSlice<'a>;
722
723 fn next(&mut self) -> Option<Self::Item> {
724 if self.offset >= self.slice.len() {
725 None
726 } else {
727 let len = std::cmp::min(self.chunk_size, self.slice.len() - self.offset);
728 let chunk = self.slice.subslice(self.offset..self.offset + len);
729 self.offset += len;
730 Some(chunk)
731 }
732 }
733}
734
735pub struct ChunksMut<'a> {
737 slice: MutPtrByteSlice<'a>,
738 chunk_size: usize,
739 offset: usize,
740}
741
742impl<'a> Iterator for ChunksMut<'a> {
743 type Item = MutPtrByteSlice<'a>;
744
745 fn next(&mut self) -> Option<Self::Item> {
746 if self.offset >= self.slice.len() {
747 None
748 } else {
749 let len = std::cmp::min(self.chunk_size, self.slice.len() - self.offset);
750 let chunk = self.slice.subslice_mut(self.offset..self.offset + len);
751 self.offset += len;
752 Some(chunk)
753 }
754 }
755}
756
757impl std::io::Read for PtrByteSlice<'_> {
758 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
759 let remaining = self.len();
760 if remaining == 0 {
761 return Ok(0);
762 }
763 let to_read = std::cmp::min(remaining, buf.len());
764 let (a, b) = self.split_at(to_read);
765 a.copy_to_slice(&mut buf[..to_read]);
766 *self = b;
767 Ok(to_read)
768 }
769
770 fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
771 if buf.len() > self.len() {
772 return Err(std::io::Error::new(
773 std::io::ErrorKind::UnexpectedEof,
774 "failed to fill whole buffer",
775 ));
776 }
777 let (a, b) = self.split_at(buf.len());
778 a.copy_to_slice(buf);
779 *self = b;
780 Ok(())
781 }
782
783 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
784 let len = self.len();
785 self.append_to(buf);
786 *self = self.subslice(len..len);
787 Ok(len)
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use super::*;
794 use std::io::{Read, Write};
795 use zerocopy::IntoBytes;
796
797 #[derive(Copy, Clone, Debug, FromBytes, IntoBytes)]
798 #[repr(C, align(4))]
799 struct Aligned4(u32);
800
801 #[test]
802 fn test_iter_as_success() {
803 let bytes = [0u8; 16];
804 let slice = PtrByteSlice::from(&bytes[..]);
805 let elems = slice.iter_as::<Aligned4>();
806 assert_eq!(elems.count(), 4);
807 }
808
809 #[test]
810 #[should_panic(expected = "Slice is not aligned to T")]
811 fn test_iter_as_unaligned_panic() {
812 #[repr(C, align(4))]
813 struct AligningBuffer {
814 buffer: [u8; 17],
815 }
816 let aligned = AligningBuffer { buffer: [0u8; 17] };
817 let slice = PtrByteSlice::from(&aligned.buffer[1..17]);
818 let _ = slice.iter_as::<Aligned4>();
819 }
820
821 #[test]
822 #[should_panic]
823 fn test_iter_as_missized_panic() {
824 let bytes = [0u8; 15];
825 let slice = PtrByteSlice::from(&bytes[..]);
826 let _ = slice.iter_as::<Aligned4>();
827 }
828
829 #[test]
830 fn test_iter_as_mut_success() {
831 let mut bytes = [0u8; 16];
832 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
833 let elems = slice.iter_as_mut::<Aligned4>();
834 assert_eq!(elems.count(), 4);
835 }
836
837 #[test]
838 #[should_panic(expected = "Slice is not aligned to T")]
839 fn test_iter_as_mut_unaligned_panic() {
840 #[repr(C, align(4))]
841 struct AligningBuffer {
842 buffer: [u8; 17],
843 }
844 let mut aligned = AligningBuffer { buffer: [0u8; 17] };
845 let mut slice = MutPtrByteSlice::from(&mut aligned.buffer[1..17]);
846 let _ = slice.iter_as_mut::<Aligned4>();
847 }
848
849 #[test]
850 #[should_panic]
851 fn test_iter_as_mut_missized_panic() {
852 let mut bytes = [0u8; 15];
853 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
854 let _ = slice.iter_as_mut::<Aligned4>();
855 }
856
857 #[test]
858 fn test_byte_chunks() {
859 let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
860 let slice = PtrByteSlice::from(&bytes[..]);
861 let chunks: Vec<_> = slice.chunks(4).map(|c| c.to_vec()).collect();
862 assert_eq!(chunks, vec![vec![1, 2, 3, 4], vec![5, 6, 7, 8], vec![9, 10]]);
863 }
864
865 #[test]
866 fn test_byte_chunks_mut() {
867 let mut bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
868 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
869 for mut chunk in slice.chunks_mut(4) {
870 chunk.fill(0);
871 }
872 assert_eq!(bytes, [0u8; 10]);
873 }
874
875 #[test]
876 fn test_reader() {
877 let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
878 let mut slice = PtrByteSlice::from(&bytes[..]);
879 let mut buf = [0u8; 4];
880 assert_eq!(Read::read(&mut slice, &mut buf).unwrap(), 4);
881 assert_eq!(buf, [1, 2, 3, 4]);
882 assert_eq!(slice.len(), 6);
883 let mut rest = Vec::new();
884 assert_eq!(slice.read_to_end(&mut rest).unwrap(), 6);
885 assert_eq!(rest, [5, 6, 7, 8, 9, 10]);
886 assert_eq!(slice.len(), 0);
887 }
888
889 #[test]
890 fn test_read_success() {
891 let bytes = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8];
892 let slice = PtrByteSlice::from(&bytes[..]);
893
894 let val = slice.read::<Aligned4>().unwrap();
895 assert_eq!(val.0, u32::from_ne_bytes([1, 2, 3, 4]));
898
899 let sub = slice.subslice(1..8);
901 let val_unaligned = sub.read::<Aligned4>().unwrap();
902 assert_eq!(val_unaligned.0, u32::from_ne_bytes([2, 3, 4, 5]));
903 }
904
905 #[test]
906 fn test_read_bounds_failure() {
907 let bytes = [1u8, 2u8, 3u8];
908 let slice = PtrByteSlice::from(&bytes[..]);
909 assert!(slice.read::<Aligned4>().is_none());
910 }
911
912 #[test]
913 fn test_mut_read_write_success() {
914 let mut bytes = [0u8; 8];
915 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
916
917 slice.write(Aligned4(0x12345678)).unwrap();
919 assert_eq!(slice.read::<Aligned4>().unwrap().0, 0x12345678);
920
921 let mut sub = slice.subslice_mut(1..8);
923 sub.write(Aligned4(0xabcdef01)).unwrap();
924 assert_eq!(sub.read::<Aligned4>().unwrap().0, 0xabcdef01);
925 }
926
927 #[test]
928 fn test_mut_write_bounds_failure() {
929 let mut bytes = [0u8; 3];
930 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
931 assert!(slice.write(Aligned4(0)).is_none());
932 }
933
934 #[test]
935 fn test_writer() {
936 let mut bytes = [0u8; 16];
937 let slice = MutPtrByteSlice::from(&mut bytes[..]);
938 let mut writer = slice.writer();
939 assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
940 assert_eq!(writer.position(), 3);
941 writer.write_all(&[4, 5, 6, 7]).unwrap();
942 assert_eq!(writer.position(), 7);
943 assert_eq!(&bytes[..7], &[1, 2, 3, 4, 5, 6, 7]);
944 }
945
946 #[test]
947 fn test_writer_write_all_error() {
948 let mut bytes = [0u8; 4];
949 let slice = MutPtrByteSlice::from(&mut bytes[..]);
950 let mut writer = slice.writer();
951 let err = writer.write_all(&[1, 2, 3, 4, 5]).unwrap_err();
952 assert_eq!(err.kind(), std::io::ErrorKind::WriteZero);
953 assert_eq!(writer.position(), 0);
954 }
955
956 #[test]
957 fn test_writer_write_full_and_remaining() {
958 let mut bytes = [0u8; 4];
959 let slice = MutPtrByteSlice::from(&mut bytes[..]);
960 let mut writer = slice.writer();
961 assert_eq!(writer.write(&[1, 2, 3, 4, 5]).unwrap(), 4);
962 assert_eq!(writer.position(), 4);
963 assert_eq!(writer.write(&[6]).unwrap(), 0);
964 assert_eq!(writer.remaining().len(), 0);
965 writer.flush().unwrap();
966 let written = writer.into_written();
967 assert_eq!(written.len(), 4);
968 assert_eq!(&bytes[..], &[1, 2, 3, 4]);
969 }
970
971 #[test]
972 fn test_zero_no_rfo() {
973 let mut bytes = [0xabu8; 256];
974 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
975 slice.zero_no_rfo();
976
977 #[cfg(target_arch = "aarch64")]
978 {
979 let addr = bytes.as_ptr() as usize;
980 let end = addr + 256;
981 let aligned_start = addr.next_multiple_of(64);
982 let aligned_end = end - end % 64;
983 if aligned_start < aligned_end {
984 let offset_start = aligned_start - addr;
985 let offset_end = aligned_end - addr;
986 assert_eq!(&bytes[offset_start..offset_end], &[0u8; 256][offset_start..offset_end]);
987 }
988 }
989 }
990}