@@ -595,6 +595,72 @@ impl<T> WrapperTypeDecode for Box<T> {
595595
596596impl < T : DecodeWithMemTracking > DecodeWithMemTracking for Box < T > { }
597597
598+ impl < T : Decode > Decode for Box < [ T ] > {
599+ fn decode < I : Input > ( input : & mut I ) -> Result < Self , Error > {
600+ let len = <Compact < u32 > >:: decode ( input) . map ( |Compact ( len) | len as usize ) ?;
601+
602+ input. descend_ref ( ) ?;
603+
604+ // Placement new is not yet stable, but we can just manually allocate a chunk of memory
605+ // and convert it to a `Box` ourselves.
606+ //
607+ // The explicit types here are written out for clarity.
608+ //
609+ // TODO: Use `Box::new_uninit_slice` once that's stable.
610+ let layout = core:: alloc:: Layout :: array :: < MaybeUninit < T > > ( len)
611+ . map_err ( |_| Error :: from ( "Item is too big and cannot be allocated" ) ) ?;
612+
613+ let ptr: * mut MaybeUninit < T > = if layout. size ( ) == 0 {
614+ core:: ptr:: NonNull :: dangling ( ) . as_ptr ( )
615+ } else {
616+ // SAFETY: Layout has a non-zero size so calling this is safe.
617+ let ptr = unsafe { crate :: alloc:: alloc:: alloc ( layout) } ;
618+
619+ if ptr. is_null ( ) {
620+ crate :: alloc:: alloc:: handle_alloc_error ( layout) ;
621+ }
622+
623+ ptr. cast ( )
624+ } ;
625+
626+ // SAFETY: Constructing a `Box` from a piece of memory allocated with `std::alloc::alloc`
627+ // is explicitly allowed as long as it was allocated with the global allocator
628+ // and the memory layout matches.
629+ //
630+ // Constructing a `Box` from `NonNull::dangling` is also always safe as long
631+ // as the underlying type is zero-sized.
632+ let mut boxed_slice: Box < [ MaybeUninit < T > ] > = unsafe {
633+ Box :: from_raw ( core:: slice:: from_raw_parts_mut ( ptr, len) )
634+ } ;
635+
636+ for elem in & mut * boxed_slice {
637+ T :: decode_into ( input, elem) ?;
638+ }
639+
640+ // Decoding succeeded, so let's get rid of `MaybeUninit`.
641+ // TODO: Use `Box::assume_init` once that's stable.
642+ let boxed_slice = Vec :: from ( boxed_slice)
643+ . into_iter ( )
644+ . map ( |elem| unsafe { MaybeUninit :: assume_init ( elem) } )
645+ . collect ( ) ;
646+
647+ input. ascend_ref ( ) ;
648+ Ok ( boxed_slice)
649+ }
650+ }
651+
652+ impl Decode for Box < str > {
653+ fn decode < I : Input > ( input : & mut I ) -> Result < Self , Error > {
654+ // Guaranteed to create a Vec with capacity == len
655+ let vec = Vec :: from ( Box :: < [ u8 ] > :: decode ( input) ?) ;
656+ // Guaranteed not to reallocate the vec, only transmute to String
657+ let str = String :: from_utf8 ( vec) . map_err ( |_| "Invalid utf8 sequence" ) ?;
658+
659+ assert_eq ! ( str . capacity( ) , str . len( ) ) ;
660+ Ok ( str. into_boxed_str ( ) )
661+ }
662+ }
663+
598664impl < T > WrapperTypeDecode for Rc < T > {
599665 type Wrapped = T ;
600666
@@ -1713,6 +1779,39 @@ mod tests {
17131779 assert_eq ! ( ( x, y) , Decode :: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
17141780 }
17151781
1782+ #[ test]
1783+ fn boxed_str_works ( ) {
1784+ let s = "Hello world" . to_owned ( ) ;
1785+ let b = s. clone ( ) . into_boxed_str ( ) ;
1786+
1787+ let encoded = b. encode ( ) ;
1788+ assert_eq ! ( s. encode( ) , encoded) ;
1789+
1790+ assert_eq ! ( * b, * Box :: <str >:: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
1791+ }
1792+
1793+ #[ test]
1794+ fn boxed_slice_of_primitives_works ( ) {
1795+ let v = vec ! [ 1u32 , 2 , 3 , 4 , 5 , 6 ] ;
1796+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1797+
1798+ let encoded = b. encode ( ) ;
1799+ assert_eq ! ( v. encode( ) , encoded) ;
1800+
1801+ assert_eq ! ( * b, * Box :: <[ u32 ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1802+ }
1803+
1804+ #[ test]
1805+ fn boxed_slice_of_strings_works ( ) {
1806+ let v = vec ! [ "mine" . to_owned( ) , "yours" . to_owned( ) , "his" . to_owned( ) ] ;
1807+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1808+
1809+ let encoded = b. encode ( ) ;
1810+ assert_eq ! ( v. encode( ) , encoded) ;
1811+
1812+ assert_eq ! ( * b, * Box :: <[ String ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1813+ }
1814+
17161815 #[ test]
17171816 fn cow_works ( ) {
17181817 let x = & [ 1u32 , 2 , 3 , 4 , 5 , 6 ] [ ..] ;
0 commit comments