Skip to content

Commit af3e52d

Browse files
committed
Add support for [T] and &[mut] [T]
1 parent f382b30 commit af3e52d

File tree

2 files changed

+82
-24
lines changed

2 files changed

+82
-24
lines changed

src/lib.rs

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -438,19 +438,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
438438
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);
439439
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);
440440

441+
unsafe impl<'bytes, T: Abomonation<'bytes>> Abomonation<'bytes> for [T] {
442+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
443+
for element in self { T::entomb(element, write)?; }
444+
Ok(())
445+
}
446+
447+
unsafe fn exhume(self_: NonNull<Self>, bytes: &'bytes mut[u8]) -> Option<&'bytes mut [u8]> {
448+
// FIXME: This constructs an &[T] to invalid data, which is UB.
449+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
450+
let self_len = self_.as_ref().len();
451+
exhume_slice(self_.as_ptr() as *mut T, self_len, bytes)
452+
}
453+
454+
fn extent(&self) -> usize {
455+
self.iter().map(T::extent).sum()
456+
}
457+
}
458+
441459
macro_rules! array_abomonate {
442460
($size:expr) => (
443461
unsafe impl<'bytes, T: Abomonation<'bytes>> Abomonation<'bytes> for [T; $size] {
444462
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
445-
entomb_slice(&self[..], write)
463+
<[T]>::entomb(&self[..], write)
446464
}
447465

448466
unsafe fn exhume(self_: NonNull<Self>, bytes: &'bytes mut[u8]) -> Option<&'bytes mut [u8]> {
449467
exhume_slice(self_.as_ptr() as *mut T, $size, bytes)
450468
}
451469

452470
fn extent(&self) -> usize {
453-
slice_extent(&self[..])
471+
<[T]>::extent(&self[..])
454472
}
455473
}
456474
)
@@ -550,30 +568,64 @@ unsafe impl<'bytes> Abomonation<'bytes> for String {
550568
}
551569
}
552570

553-
unsafe impl<'bytes, T: Abomonation<'bytes>> Abomonation<'bytes> for Vec<T> {
571+
unsafe impl<'target, 'bytes: 'target, T: Abomonation<'bytes>> Abomonation<'bytes> for &'target [T] {
554572
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
555573
write.write_all(typed_to_bytes(&self[..]))?;
556-
entomb_slice(&self[..], write)
574+
<[T]>::entomb(&self[..], write)
575+
}
576+
577+
#[inline]
578+
unsafe fn exhume(self_: NonNull<Self>, bytes: &'bytes mut [u8]) -> Option<&'bytes mut [u8]> {
579+
// FIXME: This (briefly) constructs an &[T] to invalid data, which is UB.
580+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
581+
let self_len = self_.as_ref().len();
582+
let (s, rest) = exhume_slice_ref(self_len, bytes)?;
583+
self_.as_ptr().write(s);
584+
Some(rest)
585+
}
586+
587+
fn extent(&self) -> usize {
588+
mem::size_of::<T>() * self.len() + <[T]>::extent(&self[..])
589+
}
590+
}
591+
592+
unsafe impl<'target, 'bytes: 'target, T: Abomonation<'bytes>> Abomonation<'bytes> for &'target mut [T] {
593+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
594+
<&[T]>::entomb(&&self[..], write)
595+
}
596+
597+
#[inline]
598+
unsafe fn exhume(self_: NonNull<Self>, bytes: &'bytes mut [u8]) -> Option<&'bytes mut [u8]> {
599+
// FIXME: This (briefly) constructs an &mut [T] to invalid data, which is UB.
600+
// I'm not sure if this can be fully resolved without relying on slice implementation details.
601+
let self_len = self_.as_ref().len();
602+
let (s, rest) = exhume_slice_ref(self_len, bytes)?;
603+
self_.as_ptr().write(s);
604+
Some(rest)
605+
}
606+
607+
fn extent(&self) -> usize {
608+
<&[T]>::extent(&&self[..])
609+
}
610+
}
611+
612+
unsafe impl<'bytes, T: Abomonation<'bytes>> Abomonation<'bytes> for Vec<T> {
613+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
614+
<&[T]>::entomb(&&self[..], write)
557615
}
558616

559617
#[inline]
560618
unsafe fn exhume(self_: NonNull<Self>, bytes: &'bytes mut [u8]) -> Option<&'bytes mut [u8]> {
561619
// FIXME: This (briefly) constructs an &Vec<T> to invalid data, which is UB.
562620
// I'm not sure if this can be fully resolved without relying on Vec implementation details.
563621
let self_len = self_.as_ref().len();
564-
let binary_len = self_len * mem::size_of::<T>();
565-
if binary_len > bytes.len() { None }
566-
else {
567-
let (mine, mut rest) = bytes.split_at_mut(binary_len);
568-
let first_ptr = mine.as_mut_ptr() as *mut T;
569-
rest = exhume_slice(first_ptr, self_len, rest)?;
570-
self_.as_ptr().write(Vec::from_raw_parts(first_ptr, self_len, self_len));
571-
Some(rest)
572-
}
622+
let (s, rest) = exhume_slice_ref(self_len, bytes)?;
623+
self_.as_ptr().write(Vec::from_raw_parts(s.as_mut_ptr(), self_len, self_len));
624+
Some(rest)
573625
}
574626

575627
fn extent(&self) -> usize {
576-
mem::size_of::<T>() * self.len() + slice_extent(&self[..])
628+
<&[T]>::extent(&&self[..])
577629
}
578630
}
579631

@@ -631,14 +683,8 @@ unsafe fn typed_to_bytes<T>(slice: &[T]) -> &[u8] {
631683
std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * mem::size_of::<T>())
632684
}
633685

634-
// Common subset of "entomb" for all [T]-like types
635-
unsafe fn entomb_slice<'a, T: Abomonation<'a>, W: Write>(slice: &[T], write: &mut W) -> IOResult<()> {
636-
for element in slice { T::entomb(element, write)?; }
637-
Ok(())
638-
}
639-
640686
// Common subset of "exhume" for all [T]-like types
641-
// (I'd gladly take a NonNull<[T]>, but it is too difficult to build raw pointers to slices)
687+
// (I'd gladly move this to [T]::exhume, but building a NonNull<[T]> is currently too difficult)
642688
#[inline]
643689
unsafe fn exhume_slice<'bytes, T: Abomonation<'bytes>>(
644690
first_ptr: *mut T,
@@ -652,9 +698,17 @@ unsafe fn exhume_slice<'bytes, T: Abomonation<'bytes>>(
652698
Some(bytes)
653699
}
654700

655-
// Common subset of "extent" for all [T]-like types
656-
fn slice_extent<'a, T: Abomonation<'a>>(slice: &[T]) -> usize {
657-
slice.iter().map(T::extent).sum()
701+
// Common subset of "exhume" for all &[T]-like types
702+
#[inline]
703+
unsafe fn exhume_slice_ref<'target, 'bytes: 'target, T:Abomonation<'bytes>>(length: usize, bytes: &'bytes mut [u8]) -> Option<(&'target mut [T], &'bytes mut [u8])> {
704+
let binary_len = length * mem::size_of::<T>();
705+
if binary_len > bytes.len() { None }
706+
else {
707+
let (mine, mut rest) = bytes.split_at_mut(binary_len);
708+
let first_ptr = mine.as_mut_ptr() as *mut T;
709+
rest = exhume_slice(first_ptr, length, rest)?;
710+
Some((std::slice::from_raw_parts_mut(first_ptr, length).into(), rest))
711+
}
658712
}
659713

660714
// Common subset of "exhume" for all &mut T-like types

tests/tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ gen_tests!{
9292
&"grawwwwrr!" => (test_str_pass,
9393
test_str_fail,
9494
test_str_size),
95+
96+
&[0, 1, 2] => (test_slice_pass,
97+
test_slice_fail,
98+
test_slice_size),
9599
}
96100

97101
fn _test_pass<'bytes, T: Abomonation<'bytes> + Debug + Eq>(

0 commit comments

Comments
 (0)