@@ -573,6 +573,72 @@ impl<T> WrapperTypeDecode for Box<T> {
573
573
}
574
574
}
575
575
576
+ impl < T : Decode > Decode for Box < [ T ] > {
577
+ fn decode < I : Input > ( input : & mut I ) -> Result < Self , Error > {
578
+ let len = <Compact < u32 > >:: decode ( input) . map ( |Compact ( len) | len as usize ) ?;
579
+
580
+ input. descend_ref ( ) ?;
581
+
582
+ // Placement new is not yet stable, but we can just manually allocate a chunk of memory
583
+ // and convert it to a `Box` ourselves.
584
+ //
585
+ // The explicit types here are written out for clarity.
586
+ //
587
+ // TODO: Use `Box::new_uninit_slice` once that's stable.
588
+ let layout = core:: alloc:: Layout :: array :: < MaybeUninit < T > > ( len)
589
+ . map_err ( |_| Error :: from ( "Item is too big and cannot be allocated" ) ) ?;
590
+
591
+ let ptr: * mut MaybeUninit < T > = if layout. size ( ) == 0 {
592
+ core:: ptr:: NonNull :: dangling ( ) . as_ptr ( )
593
+ } else {
594
+ // SAFETY: Layout has a non-zero size so calling this is safe.
595
+ let ptr = unsafe { crate :: alloc:: alloc:: alloc ( layout) } ;
596
+
597
+ if ptr. is_null ( ) {
598
+ crate :: alloc:: alloc:: handle_alloc_error ( layout) ;
599
+ }
600
+
601
+ ptr. cast ( )
602
+ } ;
603
+
604
+ // SAFETY: Constructing a `Box` from a piece of memory allocated with `std::alloc::alloc`
605
+ // is explicitly allowed as long as it was allocated with the global allocator
606
+ // and the memory layout matches.
607
+ //
608
+ // Constructing a `Box` from `NonNull::dangling` is also always safe as long
609
+ // as the underlying type is zero-sized.
610
+ let mut boxed_slice: Box < [ MaybeUninit < T > ] > = unsafe {
611
+ Box :: from_raw ( core:: slice:: from_raw_parts_mut ( ptr, len) )
612
+ } ;
613
+
614
+ for elem in & mut * boxed_slice {
615
+ T :: decode_into ( input, elem) ?;
616
+ }
617
+
618
+ // Decoding succeeded, so let's get rid of `MaybeUninit`.
619
+ // TODO: Use `Box::assume_init` once that's stable.
620
+ let boxed_slice = Vec :: from ( boxed_slice)
621
+ . into_iter ( )
622
+ . map ( |elem| unsafe { MaybeUninit :: assume_init ( elem) } )
623
+ . collect ( ) ;
624
+
625
+ input. ascend_ref ( ) ;
626
+ Ok ( boxed_slice)
627
+ }
628
+ }
629
+
630
+ impl Decode for Box < str > {
631
+ fn decode < I : Input > ( input : & mut I ) -> Result < Self , Error > {
632
+ // Guaranteed to create a Vec with capacity == len
633
+ let vec = Vec :: from ( Box :: < [ u8 ] > :: decode ( input) ?) ;
634
+ // Guaranteed not to reallocate the vec, only transmute to String
635
+ let str = String :: from_utf8 ( vec) . map_err ( |_| "Invalid utf8 sequence" ) ?;
636
+
637
+ assert_eq ! ( str . capacity( ) , str . len( ) ) ;
638
+ Ok ( str. into_boxed_str ( ) )
639
+ }
640
+ }
641
+
576
642
impl < T > WrapperTypeDecode for Rc < T > {
577
643
type Wrapped = T ;
578
644
@@ -1612,6 +1678,39 @@ mod tests {
1612
1678
assert_eq ! ( ( x, y) , Decode :: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
1613
1679
}
1614
1680
1681
+ #[ test]
1682
+ fn boxed_str_works ( ) {
1683
+ let s = "Hello world" . to_owned ( ) ;
1684
+ let b = s. clone ( ) . into_boxed_str ( ) ;
1685
+
1686
+ let encoded = b. encode ( ) ;
1687
+ assert_eq ! ( s. encode( ) , encoded) ;
1688
+
1689
+ assert_eq ! ( * b, * Box :: <str >:: decode( & mut & encoded[ ..] ) . unwrap( ) ) ;
1690
+ }
1691
+
1692
+ #[ test]
1693
+ fn boxed_slice_of_primitives_works ( ) {
1694
+ let v = vec ! [ 1u32 , 2 , 3 , 4 , 5 , 6 ] ;
1695
+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1696
+
1697
+ let encoded = b. encode ( ) ;
1698
+ assert_eq ! ( v. encode( ) , encoded) ;
1699
+
1700
+ assert_eq ! ( * b, * Box :: <[ u32 ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1701
+ }
1702
+
1703
+ #[ test]
1704
+ fn boxed_slice_of_strings_works ( ) {
1705
+ let v = vec ! [ "mine" . to_owned( ) , "yours" . to_owned( ) , "his" . to_owned( ) ] ;
1706
+ let b = v. clone ( ) . into_boxed_slice ( ) ;
1707
+
1708
+ let encoded = b. encode ( ) ;
1709
+ assert_eq ! ( v. encode( ) , encoded) ;
1710
+
1711
+ assert_eq ! ( * b, * Box :: <[ String ] >:: decode( & mut & b. encode( ) [ ..] ) . unwrap( ) ) ;
1712
+ }
1713
+
1615
1714
#[ test]
1616
1715
fn cow_works ( ) {
1617
1716
let x = & [ 1u32 , 2 , 3 , 4 , 5 , 6 ] [ ..] ;
0 commit comments