@@ -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+
566582mod network {
567583 use Abomonation ;
568584 use std:: net:: { SocketAddr , SocketAddrV4 , SocketAddrV6 , IpAddr , Ipv4Addr , Ipv6Addr } ;
0 commit comments