Skip to content

Commit c1b1067

Browse files
committed
Add implementation of Decode for Box<str> and Box<[T]>
Signed-off-by: Marin Veršić <[email protected]>
1 parent 805816a commit c1b1067

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

src/codec.rs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,7 @@ impl<T> WrapperTypeDecode for Box<T> {
537537
} else {
538538

539539
// SAFETY: Layout has a non-zero size so calling this is safe.
540-
let ptr: *mut u8 = unsafe {
541-
crate::alloc::alloc::alloc(layout)
542-
};
540+
let ptr = unsafe { crate::alloc::alloc::alloc(layout) };
543541

544542
if ptr.is_null() {
545543
crate::alloc::alloc::handle_alloc_error(layout);
@@ -554,25 +552,42 @@ impl<T> WrapperTypeDecode for Box<T> {
554552
//
555553
// Constructing a `Box` from `NonNull::dangling` is also always safe as long
556554
// as the underlying type is zero-sized.
557-
let mut boxed: Box<MaybeUninit<T>> = unsafe { Box::from_raw(ptr) };
558-
555+
let mut boxed = unsafe { Box::from_raw(ptr) };
559556
T::decode_into(input, &mut boxed)?;
560557

561558
// Decoding succeeded, so let's get rid of `MaybeUninit`.
562559
//
563560
// TODO: Use `Box::assume_init` once that's stable.
564-
let ptr: *mut MaybeUninit<T> = Box::into_raw(boxed);
565-
let ptr: *mut T = ptr.cast();
561+
let ptr: *mut T = Box::into_raw(boxed).cast();
566562

567563
// SAFETY: `MaybeUninit` doesn't affect the memory layout, so casting the pointer back
568564
// into a `Box` is safe.
569-
let boxed: Box<T> = unsafe { Box::from_raw(ptr) };
565+
let boxed = unsafe { Box::from_raw(ptr) };
570566

571567
input.ascend_ref();
572568
Ok(boxed)
573569
}
574570
}
575571

572+
impl<T: Decode> Decode for Box<[T]> {
573+
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
574+
Ok(Vec::decode(input)?.into_boxed_slice())
575+
}
576+
}
577+
578+
impl Decode for Box<str> {
579+
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
580+
// Guaranteed to create a Vec with capacity == len
581+
let vec = Vec::from(Box::<[u8]>::decode(input)?);
582+
// Guaranteed not to reallocate the vec, only transmute to String
583+
let str = String::from_utf8(vec).map_err(|_| "Invalid utf8 sequence")?;
584+
585+
// At this point we have String with capacity == len,
586+
// therefore String::into_boxed_str will not reallocate
587+
Ok(str.into_boxed_str())
588+
}
589+
}
590+
576591
impl<T> WrapperTypeDecode for Rc<T> {
577592
type Wrapped = T;
578593

@@ -1612,6 +1627,28 @@ mod tests {
16121627
assert_eq!((x, y), Decode::decode(&mut &encoded[..]).unwrap());
16131628
}
16141629

1630+
#[test]
1631+
fn boxed_str_works() {
1632+
let s = "Hello world".to_owned();
1633+
let b = s.clone().into_boxed_str();
1634+
1635+
let encoded = b.encode();
1636+
assert_eq!(s.encode(), encoded);
1637+
1638+
assert_eq!(*b, *Box::<str>::decode(&mut &encoded[..]).unwrap());
1639+
}
1640+
1641+
#[test]
1642+
fn boxed_slice_works() {
1643+
let v = vec![1u32, 2, 3, 4, 5, 6];
1644+
let b = v.clone().into_boxed_slice();
1645+
1646+
let encoded = b.encode();
1647+
assert_eq!(v.encode(), encoded);
1648+
1649+
assert_eq!(*b, *Box::<[u32]>::decode(&mut &b.encode()[..]).unwrap());
1650+
}
1651+
16151652
#[test]
16161653
fn cow_works() {
16171654
let x = &[1u32, 2, 3, 4, 5, 6][..];

0 commit comments

Comments
 (0)