Skip to content

Commit f7b151a

Browse files
committed
Port slice-like abomonations to NonNull-based interface (and deduplicate them)
1 parent 60fe3fe commit f7b151a

File tree

1 file changed

+48
-32
lines changed

1 file changed

+48
-32
lines changed

src/lib.rs

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -424,22 +424,16 @@ macro_rules! array_abomonate {
424424
impl<T: Abomonation> Abomonation for [T; $size] {
425425
#[inline(always)]
426426
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
427-
for element in self { element.entomb(write)?; }
428-
Ok(())
427+
entomb_slice(self.as_ref(), write)
429428
}
429+
430430
#[inline(always)]
431-
unsafe fn exhume<'a>(self_: NonNull<Self>, mut bytes: &'a mut[u8]) -> Option<&'a mut [u8]> {
432-
for element in self {
433-
let tmp = bytes; bytes = element.exhume(tmp)?;
434-
}
435-
Some(bytes)
431+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut[u8]) -> Option<&'a mut [u8]> {
432+
exhume_slice(self_.as_ptr() as *mut T, $size, bytes)
436433
}
434+
437435
#[inline(always)] fn extent(&self) -> usize {
438-
let mut size = 0;
439-
for element in self {
440-
size += element.extent();
441-
}
442-
size
436+
slice_extent(self.as_ref())
443437
}
444438
}
445439
)
@@ -485,15 +479,20 @@ impl Abomonation for String {
485479
write.write_all(self.as_bytes())?;
486480
Ok(())
487481
}
482+
488483
#[inline]
489-
unsafe fn exhume<'a>(Self: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
490-
if self.len() > bytes.len() { None }
484+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
485+
// FIXME: This (briefly) constructs an &String to invalid data, which is UB.
486+
// I'm not sure if this can be fully resolved without relying on String implementation details.
487+
let self_len = self_.as_ref().len();
488+
if self_len > bytes.len() { None }
491489
else {
492-
let (mine, rest) = bytes.split_at_mut(self.len());
493-
std::ptr::write(self, String::from_raw_parts(mem::transmute(mine.as_ptr()), self.len(), self.len()));
490+
let (mine, rest) = bytes.split_at_mut(self_len);
491+
self_.as_ptr().write(String::from_raw_parts(mine.as_mut_ptr(), self_len, self_len));
494492
Some(rest)
495493
}
496494
}
495+
497496
#[inline] fn extent(&self) -> usize {
498497
self.len()
499498
}
@@ -503,33 +502,28 @@ impl<T: Abomonation> Abomonation for Vec<T> {
503502
#[inline]
504503
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
505504
write.write_all(typed_to_bytes(&self[..]))?;
506-
for element in self.iter() { element.entomb(write)?; }
507-
Ok(())
505+
entomb_slice(self.as_ref(), write)
508506
}
507+
509508
#[inline]
510509
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
511-
512-
// extract memory from bytes to back our vector
513-
let binary_len = self.len() * mem::size_of::<T>();
510+
// FIXME: This (briefly) constructs an &Vec<T> to invalid data, which is UB.
511+
// I'm not sure if this can be fully resolved without relying on Vec implementation details.
512+
let self_len = self_.as_ref().len();
513+
let binary_len = self_len * mem::size_of::<T>();
514514
if binary_len > bytes.len() { None }
515515
else {
516516
let (mine, mut rest) = bytes.split_at_mut(binary_len);
517-
let slice = std::slice::from_raw_parts_mut(mine.as_mut_ptr() as *mut T, self.len());
518-
std::ptr::write(self, Vec::from_raw_parts(slice.as_mut_ptr(), self.len(), self.len()));
519-
for element in self.iter_mut() {
520-
let temp = rest; // temp variable explains lifetimes (mysterious!)
521-
rest = element.exhume(temp)?;
522-
}
517+
let first_ptr = mine.as_mut_ptr() as *mut T;
518+
rest = exhume_slice(first_ptr, self_len, rest)?;
519+
self_.as_ptr().write(Vec::from_raw_parts(first_ptr, self_len, self_len));
523520
Some(rest)
524521
}
525522
}
523+
526524
#[inline]
527525
fn extent(&self) -> usize {
528-
let mut sum = mem::size_of::<T>() * self.len();
529-
for element in self.iter() {
530-
sum += element.extent();
531-
}
532-
sum
526+
mem::size_of::<T>() * self.len() + slice_extent(self.as_ref())
533527
}
534528
}
535529

@@ -563,6 +557,28 @@ impl<T: Abomonation> Abomonation for Box<T> {
563557
std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * mem::size_of::<T>())
564558
}
565559

560+
// Common subset of "entomb" for all [T]-like types
561+
unsafe fn entomb_slice<T: Abomonation, W: Write>(slice: &[T], write: &mut W) -> IOResult<()> {
562+
for element in slice { element.entomb(write)?; }
563+
Ok(())
564+
}
565+
566+
// Common subset of "exhume" for all [T]-like types
567+
// (I'd gladly take a NonNull<[T]>, but it is too difficult to build raw pointers to slices)
568+
#[inline]
569+
unsafe fn exhume_slice<'a, T: Abomonation>(first_ptr: *mut T, length: usize, mut bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
570+
for i in 0..length {
571+
let element_ptr: NonNull<T> = NonNull::new_unchecked(first_ptr.add(i));
572+
bytes = T::exhume(element_ptr, bytes)?;
573+
}
574+
Some(bytes)
575+
}
576+
577+
// Common subset of "extent" for all [T]-like types
578+
fn slice_extent<T: Abomonation>(slice: &[T]) -> usize {
579+
slice.iter().map(T::extent).sum()
580+
}
581+
566582
mod network {
567583
use Abomonation;
568584
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr};

0 commit comments

Comments
 (0)