Skip to content

Commit 984c99c

Browse files
committed
Add implementation of Decode for Box<str> and Box<[T]>
Signed-off-by: Marin Veršić <marin.versic101@gmail.com>
1 parent 805816a commit 984c99c

File tree

1 file changed

+45
-7
lines changed

1 file changed

+45
-7
lines changed

src/codec.rs

Lines changed: 45 additions & 7 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,43 @@ 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);
561+
let ptr = Box::into_raw(boxed);
565562
let ptr: *mut T = ptr.cast();
566563

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

571568
input.ascend_ref();
572569
Ok(boxed)
573570
}
574571
}
575572

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

@@ -1612,6 +1628,28 @@ mod tests {
16121628
assert_eq!((x, y), Decode::decode(&mut &encoded[..]).unwrap());
16131629
}
16141630

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

0 commit comments

Comments
 (0)