Skip to content

Commit 9b4ebdc

Browse files
committed
Add support for [T] and &[mut] [T]
1 parent 79ae836 commit 9b4ebdc

File tree

2 files changed

+81
-24
lines changed

2 files changed

+81
-24
lines changed

src/lib.rs

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -429,19 +429,37 @@ tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD
429429
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE);
430430
tuple_abomonate!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE AF);
431431

432+
unsafe impl<T: Abomonation> Abomonation for [T] {
433+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
434+
for element in self { T::entomb(element, write)?; }
435+
Ok(())
436+
}
437+
438+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut[u8]) -> Option<&'a mut [u8]> {
439+
// FIXME: This constructs an &[T] to invalid data, which is UB.
440+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
441+
let self_len = self_.as_ref().len();
442+
exhume_slice(self_.as_ptr() as *mut T, self_len, bytes)
443+
}
444+
445+
fn extent(&self) -> usize {
446+
self.iter().map(T::extent).sum()
447+
}
448+
}
449+
432450
macro_rules! array_abomonate {
433451
($size:expr) => (
434452
unsafe impl<T: Abomonation> Abomonation for [T; $size] {
435453
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
436-
entomb_slice(&self[..], write)
454+
<[T]>::entomb(&self[..], write)
437455
}
438456

439457
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut[u8]) -> Option<&'a mut [u8]> {
440458
exhume_slice(self_.as_ptr() as *mut T, $size, bytes)
441459
}
442460

443461
fn extent(&self) -> usize {
444-
slice_extent(&self[..])
462+
<[T]>::extent(&self[..])
445463
}
446464
}
447465
)
@@ -541,30 +559,64 @@ unsafe impl Abomonation for String {
541559
}
542560
}
543561

544-
unsafe impl<T: Abomonation> Abomonation for Vec<T> {
562+
unsafe impl<T: Abomonation> Abomonation for &'_ [T] {
545563
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
546564
write.write_all(typed_to_bytes(&self[..]))?;
547-
entomb_slice(&self[..], write)
565+
<[T]>::entomb(&self[..], write)
566+
}
567+
568+
#[inline]
569+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
570+
// FIXME: This (briefly) constructs an &[T] to invalid data, which is UB.
571+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
572+
let self_len = self_.as_ref().len();
573+
let (s, rest) = exhume_slice_ref(self_len, bytes)?;
574+
self_.as_ptr().write(s.as_ref());
575+
Some(rest)
576+
}
577+
578+
fn extent(&self) -> usize {
579+
mem::size_of::<T>() * self.len() + <[T]>::extent(&self[..])
580+
}
581+
}
582+
583+
unsafe impl<T: Abomonation> Abomonation for &'_ mut [T] {
584+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
585+
<&[T]>::entomb(&&self[..], write)
586+
}
587+
588+
#[inline]
589+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
590+
// FIXME: This (briefly) constructs an &mut [T] to invalid data, which is UB.
591+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
592+
let self_len = self_.as_ref().len();
593+
let (mut s, rest) = exhume_slice_ref(self_len, bytes)?;
594+
self_.as_ptr().write(s.as_mut());
595+
Some(rest)
596+
}
597+
598+
fn extent(&self) -> usize {
599+
<&[T]>::extent(&&self[..])
600+
}
601+
}
602+
603+
unsafe impl<T: Abomonation> Abomonation for Vec<T> {
604+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
605+
<&[T]>::entomb(&&self[..], write)
548606
}
549607

550608
#[inline]
551609
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
552610
// FIXME: This (briefly) constructs an &Vec<T> to invalid data, which is UB.
553611
// I'm not sure if this can be fully resolved without relying on Vec implementation details.
554612
let self_len = self_.as_ref().len();
555-
let binary_len = self_len * mem::size_of::<T>();
556-
if binary_len > bytes.len() { None }
557-
else {
558-
let (mine, mut rest) = bytes.split_at_mut(binary_len);
559-
let first_ptr = mine.as_mut_ptr() as *mut T;
560-
rest = exhume_slice(first_ptr, self_len, rest)?;
561-
self_.as_ptr().write(Vec::from_raw_parts(first_ptr, self_len, self_len));
562-
Some(rest)
563-
}
613+
let (mut s, rest) = exhume_slice_ref(self_len, bytes)?;
614+
self_.as_ptr().write(Vec::from_raw_parts(s.as_mut().as_mut_ptr(), self_len, self_len));
615+
Some(rest)
564616
}
565617

566618
fn extent(&self) -> usize {
567-
mem::size_of::<T>() * self.len() + slice_extent(&self[..])
619+
<&[T]>::extent(&&self[..])
568620
}
569621
}
570622

@@ -622,14 +674,8 @@ unsafe fn typed_to_bytes<T>(slice: &[T]) -> &[u8] {
622674
std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * mem::size_of::<T>())
623675
}
624676

625-
// Common subset of "entomb" for all [T]-like types
626-
unsafe fn entomb_slice<T: Abomonation, W: Write>(slice: &[T], write: &mut W) -> IOResult<()> {
627-
for element in slice { T::entomb(element, write)?; }
628-
Ok(())
629-
}
630-
631677
// Common subset of "exhume" for all [T]-like types
632-
// (I'd gladly take a NonNull<[T]>, but it is too difficult to build raw pointers to slices)
678+
// (I'd gladly move this to [T]::extent, but building a NonNull<[T]> is currently too difficult)
633679
#[inline]
634680
unsafe fn exhume_slice<'a, T: Abomonation>(first_ptr: *mut T, length: usize, mut bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
635681
for i in 0..length {
@@ -639,9 +685,17 @@ unsafe fn exhume_slice<'a, T: Abomonation>(first_ptr: *mut T, length: usize, mut
639685
Some(bytes)
640686
}
641687

642-
// Common subset of "extent" for all [T]-like types
643-
fn slice_extent<T: Abomonation>(slice: &[T]) -> usize {
644-
slice.iter().map(T::extent).sum()
688+
// Common subset of "exhume" for all &[T]-like types
689+
#[inline]
690+
unsafe fn exhume_slice_ref<'a, T:Abomonation>(length: usize, bytes: &'a mut [u8]) -> Option<(NonNull<[T]>, &'a mut [u8])> {
691+
let binary_len = length * mem::size_of::<T>();
692+
if binary_len > bytes.len() { None }
693+
else {
694+
let (mine, mut rest) = bytes.split_at_mut(binary_len);
695+
let first_ptr = mine.as_mut_ptr() as *mut T;
696+
rest = exhume_slice(first_ptr, length, rest)?;
697+
Some((std::slice::from_raw_parts_mut(first_ptr, length).into(), rest))
698+
}
645699
}
646700

647701
// Common subset of "exhume" for all NonNull<T>-like types

tests/tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use std::fmt::Debug;
1717
#[test] fn test_vec_u_s_pass() { _test_pass(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
1818
#[test] fn test_ref_u64_pass() { _test_pass(vec![Some(&42u64); 1024]); }
1919
#[test] fn test_str_pass() { _test_pass(vec![&"grawwwwrr!"; 1024]); }
20+
#[test] fn test_slice_pass() { _test_pass(vec![&[0, 1, 2]; 1024]); }
2021

2122
#[test] fn test_u64_fail() { _test_fail(vec![0u64; 1024]); }
2223
#[test] fn test_u128_fail() { _test_fail(vec![0u128; 1024]); }
2324
#[test] fn test_string_fail() { _test_fail(vec![format!("grawwwwrr!"); 1024]); }
2425
#[test] fn test_vec_u_s_fail() { _test_fail(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
2526
#[test] fn test_ref_u64_fail() { _test_fail(vec![Some(&42u64); 1024]); }
2627
#[test] fn test_str_fail() { _test_fail(vec![&"grawwwwrr!"; 1024]); }
28+
#[test] fn test_slice_fail() { _test_fail(vec![&[0, 1, 2]; 1024]); }
2729

2830
#[test] fn test_array_size() { _test_size(vec![[0, 1, 2]; 1024]); }
2931
#[test] fn test_opt_vec_size() { _test_size(vec![Some(vec![0,1,2]), None]); }
@@ -38,6 +40,7 @@ use std::fmt::Debug;
3840
#[test] fn test_vec_u_s_size() { _test_size(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
3941
#[test] fn test_ref_u64_size() { _test_size(vec![Some(&42u64); 1024]); }
4042
#[test] fn test_str_size() { _test_size(vec![&"grawwwwrr!"; 1024]); }
43+
#[test] fn test_slice_size() { _test_fail(vec![&[0, 1, 2]; 1024]); }
4144

4245
#[test]
4346
fn test_phantom_data_for_non_abomonatable_type() {

0 commit comments

Comments
 (0)