@@ -595,6 +595,77 @@ impl<T> WrapperTypeDecode for Box<T> {
595
595
596
596
impl < T : DecodeWithMemTracking > DecodeWithMemTracking for Box < T > { }
597
597
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
+ input. on_before_alloc_mem ( layout. size ( ) ) ?;
614
+ let ptr: * mut MaybeUninit < T > = if layout. size ( ) == 0 {
615
+ core:: ptr:: NonNull :: dangling ( ) . as_ptr ( )
616
+ } else {
617
+ // SAFETY: Layout has a non-zero size so calling this is safe.
618
+ let ptr = unsafe { crate :: alloc:: alloc:: alloc ( layout) } ;
619
+
620
+ if ptr. is_null ( ) {
621
+ crate :: alloc:: alloc:: handle_alloc_error ( layout) ;
622
+ }
623
+
624
+ ptr. cast ( )
625
+ } ;
626
+
627
+ // SAFETY: Constructing a `Box` from a piece of memory allocated with `std::alloc::alloc`
628
+ // is explicitly allowed as long as it was allocated with the global allocator
629
+ // and the memory layout matches.
630
+ //
631
+ // Constructing a `Box` from `NonNull::dangling` is also always safe as long
632
+ // as the underlying type is zero-sized.
633
+ let mut boxed_slice: Box < [ MaybeUninit < T > ] > = unsafe {
634
+ Box :: from_raw ( core:: slice:: from_raw_parts_mut ( ptr, len) )
635
+ } ;
636
+
637
+ for elem in & mut * boxed_slice {
638
+ T :: decode_into ( input, elem) ?;
639
+ }
640
+
641
+ // Decoding succeeded, so let's get rid of `MaybeUninit`.
642
+ // TODO: Use `Box::assume_init` once that's stable.
643
+ let boxed_slice = Vec :: from ( boxed_slice)
644
+ . into_iter ( )
645
+ . map ( |elem| unsafe { MaybeUninit :: assume_init ( elem) } )
646
+ . collect ( ) ;
647
+
648
+ input. ascend_ref ( ) ;
649
+ Ok ( boxed_slice)
650
+ }
651
+ }
652
+
653
+ impl < T : DecodeWithMemTracking > DecodeWithMemTracking for Box < [ T ] > { }
654
+
655
+ impl Decode for Box < str > {
656
+ fn decode < I : Input > ( input : & mut I ) -> Result < Self , Error > {
657
+ // Guaranteed to create a Vec with capacity == len
658
+ let vec = Vec :: from ( Box :: < [ u8 ] > :: decode ( input) ?) ;
659
+ // Guaranteed not to reallocate the vec, only transmute to String
660
+ let str = String :: from_utf8 ( vec) . map_err ( |_| "Invalid utf8 sequence" ) ?;
661
+
662
+ assert_eq ! ( str . capacity( ) , str . len( ) ) ;
663
+ Ok ( str. into_boxed_str ( ) )
664
+ }
665
+ }
666
+
667
+ impl DecodeWithMemTracking for Box < str > { }
668
+
598
669
impl < T > WrapperTypeDecode for Rc < T > {
599
670
type Wrapped = T ;
600
671
@@ -1713,6 +1784,39 @@ mod tests {
1713
1784
assert_eq ! ( ( x, y) , Decode :: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
1714
1785
}
1715
1786
1787
+ #[ test]
1788
+ fn boxed_str_works ( ) {
1789
+ let s = "Hello world" . to_owned ( ) ;
1790
+ let b = s. clone ( ) . into_boxed_str ( ) ;
1791
+
1792
+ let encoded = b. encode ( ) ;
1793
+ assert_eq ! ( s. encode( ) , encoded) ;
1794
+
1795
+ assert_eq ! ( * b, * Box :: <str >:: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
1796
+ }
1797
+
1798
+ #[ test]
1799
+ fn boxed_slice_of_primitives_works ( ) {
1800
+ let v = vec ! [ 1u32 , 2 , 3 , 4 , 5 , 6 ] ;
1801
+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1802
+
1803
+ let encoded = b. encode ( ) ;
1804
+ assert_eq ! ( v. encode( ) , encoded) ;
1805
+
1806
+ assert_eq ! ( * b, * Box :: <[ u32 ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1807
+ }
1808
+
1809
+ #[ test]
1810
+ fn boxed_slice_of_strings_works ( ) {
1811
+ let v = vec ! [ "mine" . to_owned( ) , "yours" . to_owned( ) , "his" . to_owned( ) ] ;
1812
+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1813
+
1814
+ let encoded = b. encode ( ) ;
1815
+ assert_eq ! ( v. encode( ) , encoded) ;
1816
+
1817
+ assert_eq ! ( * b, * Box :: <[ String ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1818
+ }
1819
+
1716
1820
#[ test]
1717
1821
fn cow_works ( ) {
1718
1822
let x = & [ 1u32 , 2 , 3 , 4 , 5 , 6 ] [ ..] ;
0 commit comments