diff --git a/src/codec.rs b/src/codec.rs index 08f4640b..8f44003c 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -537,9 +537,7 @@ impl WrapperTypeDecode for Box { } else { // SAFETY: Layout has a non-zero size so calling this is safe. - let ptr: *mut u8 = unsafe { - crate::alloc::alloc::alloc(layout) - }; + let ptr = unsafe { crate::alloc::alloc::alloc(layout) }; if ptr.is_null() { crate::alloc::alloc::handle_alloc_error(layout); @@ -554,25 +552,42 @@ impl WrapperTypeDecode for Box { // // Constructing a `Box` from `NonNull::dangling` is also always safe as long // as the underlying type is zero-sized. - let mut boxed: Box> = unsafe { Box::from_raw(ptr) }; - + let mut boxed = unsafe { Box::from_raw(ptr) }; T::decode_into(input, &mut boxed)?; // Decoding succeeded, so let's get rid of `MaybeUninit`. // // TODO: Use `Box::assume_init` once that's stable. - let ptr: *mut MaybeUninit = Box::into_raw(boxed); - let ptr: *mut T = ptr.cast(); + let ptr: *mut T = Box::into_raw(boxed).cast(); // SAFETY: `MaybeUninit` doesn't affect the memory layout, so casting the pointer back // into a `Box` is safe. - let boxed: Box = unsafe { Box::from_raw(ptr) }; + let boxed = unsafe { Box::from_raw(ptr) }; input.ascend_ref(); Ok(boxed) } } +impl Decode for Box<[T]> { + fn decode(input: &mut I) -> Result { + Ok(Vec::decode(input)?.into_boxed_slice()) + } +} + +impl Decode for Box { + fn decode(input: &mut I) -> Result { + // Guaranteed to create a Vec with capacity == len + let vec = Vec::from(Box::<[u8]>::decode(input)?); + // Guaranteed not to reallocate the vec, only transmute to String + let str = String::from_utf8(vec).map_err(|_| "Invalid utf8 sequence")?; + + // At this point we have String with capacity == len, + // therefore String::into_boxed_str will not reallocate + Ok(str.into_boxed_str()) + } +} + impl WrapperTypeDecode for Rc { type Wrapped = T; @@ -1612,6 +1627,28 @@ mod tests { assert_eq!((x, y), Decode::decode(&mut &encoded[..]).unwrap()); } + #[test] + fn boxed_str_works() { + let s = "Hello world".to_owned(); + let b = s.clone().into_boxed_str(); + + let encoded = b.encode(); + assert_eq!(s.encode(), encoded); + + assert_eq!(*b, *Box::::decode(&mut &encoded[..]).unwrap()); + } + + #[test] + fn boxed_slice_works() { + let v = vec![1u32, 2, 3, 4, 5, 6]; + let b = v.clone().into_boxed_slice(); + + let encoded = b.encode(); + assert_eq!(v.encode(), encoded); + + assert_eq!(*b, *Box::<[u32]>::decode(&mut &b.encode()[..]).unwrap()); + } + #[test] fn cow_works() { let x = &[1u32, 2, 3, 4, 5, 6][..];