diff --git a/README.md b/README.md index f87a7e4b..bf392444 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,10 @@ v.sort(); ## Feature List - `allocator-api` (nightly): uses the `allocator-api` backend - for the allocator API + for the allocator API - `allocator-api2`: uses the `allocator-api2` backend for the allocator API - `arbitrary`: implements `Arbitrary` for any `SmallVec` storing elements - that implement `Arbitrary` + that implement `Arbitrary` - `borsh`: implements `BorshSerialize`, `BorshDeserialize` and `BorshSchema` - `bytes`: implements `BufMut` for SmallVec - `defmt`: implements `defmt::Format` for SmallVec @@ -64,7 +64,7 @@ v.sort(); - `rayon`: implements parallel iteration - `serde`: implements serde's serialization and deserialization - `specialization` (nightly): enables specialization, - improving performance on some cases + improving performance on some cases - `std`: implements the `std::io::Write` type for `SmallVec` - `zeroize`: implements `zeroize::Zeroize`, erasing elements and storage @@ -73,4 +73,4 @@ v.sort(); > - SmallVec without any features enabled does not make use of the standard library. > - The `rayon` and `proptest` features implicitly require `std`. > - The `allocator-api2` feature requires `allocator-api`, though it does not - require `nightly` +> require `nightly` diff --git a/src/allocator/boxed.rs b/src/allocator/boxed.rs index 7fa4cf9a..76afb401 100644 --- a/src/allocator/boxed.rs +++ b/src/allocator/boxed.rs @@ -2,18 +2,42 @@ use { super::{ Allocator, like::Like, - requirement::Requirement + vec::Vec }, - core::marker::PhantomData + core::{ + marker::PhantomData, + mem::MaybeUninit, + ptr::NonNull + } }; -pub struct Box(PhantomData<(Heap, Item)>); +pub struct Box(PhantomData<(Heap, Item)>); -impl Like for Box { +impl Like for Box<[Item], Heap> { + type Heap = Heap; + type Item = Item; #[cfg(not(feature = "allocator-api"))] - type Type = alloc::boxed::Box; + type Type = alloc::boxed::Box<[Item]>; #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] - type Type = alloc::boxed::Box; + type Type = alloc::boxed::Box<[Item], Heap>; #[cfg(feature = "allocator-api2")] - type Type = allocator_api2::boxed::Box; + type Type = allocator_api2::boxed::Box<[Item], Heap>; + + fn destruct( + value: Self::Type + ) -> ( + Option]>>, + usize, + Self::Heap + ) { + as Like>::destruct(value.into_vec()) + } + + fn construct( + pointer: Option]>>, + length: usize, + allocator: Self::Heap + ) -> Self::Type { + as Like>::construct(pointer, length, allocator).into_boxed_slice() + } } diff --git a/src/allocator/implementations/base.rs b/src/allocator/implementations.rs similarity index 51% rename from src/allocator/implementations/base.rs rename to src/allocator/implementations.rs index 996586fd..b93bda7e 100644 --- a/src/allocator/implementations/base.rs +++ b/src/allocator/implementations.rs @@ -1,12 +1,16 @@ +#[cfg(not(feature = "allocator-api"))] use { - super::super::{ - Allocator, - global::Global - }, + super::global::Global, alloc::alloc::{ alloc, dealloc, realloc + } +}; +use { + super::{ + Allocator, + requirement::Requirement }, core::{ alloc::Layout, @@ -14,7 +18,11 @@ use { } }; -impl Allocator for Global { +#[cfg(not(feature = "allocator-api"))] +impl Requirement for Global {} + +#[cfg(not(feature = "allocator-api"))] +impl Allocator for Type { #[inline] fn allocate(&self, layout: Layout) -> Option> { Some(NonNull::slice_from_raw_parts( @@ -49,3 +57,31 @@ impl Allocator for Global { )) } } + +#[cfg(feature = "allocator-api")] +impl Allocator for Type { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + Requirement::allocate(&self, layout).ok() + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { Requirement::deallocate(&self, pointer, layout) } + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { Requirement::grow(&self, pointer, old, new).ok() } + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { Requirement::shrink(&self, pointer, old, new).ok() } + } +} diff --git a/src/allocator/implementations/external.rs b/src/allocator/implementations/external.rs deleted file mode 100644 index 72083f23..00000000 --- a/src/allocator/implementations/external.rs +++ /dev/null @@ -1,35 +0,0 @@ -use { - super::super::Allocator, - allocator_api2::alloc::Allocator as External, - core::{ - alloc::Layout, - ptr::NonNull - } -}; - -impl Allocator for Type { - #[inline] - fn allocate(&self, layout: Layout) -> Option> { - External::allocate(&self, layout).ok() - } - - #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { External::deallocate(&self, pointer, layout) } - } - - #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - unsafe { External::grow(&self, pointer, old, new).ok() } - } - - #[inline] - unsafe fn shrink( - &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - unsafe { External::shrink(&self, pointer, old, new).ok() } - } -} diff --git a/src/allocator/implementations/mod.rs b/src/allocator/implementations/mod.rs deleted file mode 100644 index 59ab2e1e..00000000 --- a/src/allocator/implementations/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[cfg(not(feature = "allocator-api"))] -mod base; -#[cfg(feature = "allocator-api2")] -mod external; -#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] -mod native; diff --git a/src/allocator/implementations/native.rs b/src/allocator/implementations/native.rs deleted file mode 100644 index 70ef0866..00000000 --- a/src/allocator/implementations/native.rs +++ /dev/null @@ -1,35 +0,0 @@ -use { - super::super::Allocator, - alloc::alloc::Allocator as Native, - core::{ - alloc::Layout, - ptr::NonNull - } -}; - -impl Allocator for Type { - #[inline] - fn allocate(&self, layout: Layout) -> Option> { - Native::allocate(&self, layout).ok() - } - - #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { Native::deallocate(&self, pointer, layout) } - } - - #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - unsafe { Native::grow(&self, pointer, old, new).ok() } - } - - #[inline] - unsafe fn shrink( - &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - unsafe { Native::shrink(&self, pointer, old, new).ok() } - } -} diff --git a/src/allocator/like.rs b/src/allocator/like.rs index 593bdbef..8f748d64 100644 --- a/src/allocator/like.rs +++ b/src/allocator/like.rs @@ -1,3 +1,25 @@ +use { + super::Allocator, + core::{ + mem::MaybeUninit, + ptr::NonNull + } +}; + pub trait Like { type Type; + type Item; + type Heap: Allocator; + fn destruct( + value: Self::Type + ) -> ( + Option]>>, + usize, + Self::Heap + ); + fn construct( + pointer: Option]>>, + length: usize, + allocator: Self::Heap + ) -> Self::Type; } diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 074f7190..2e0b7b8a 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,17 +1,20 @@ pub mod boxed; pub mod global; -mod implementations; +pub mod implementations; pub mod like; pub mod proxy; -mod requirement; +pub mod requirement; pub mod vec; -use core::{ - alloc::Layout, - ptr::NonNull +use { + core::{ + alloc::Layout, + ptr::NonNull + }, + requirement::Requirement }; -pub trait Allocator { +pub trait Allocator: Requirement { fn allocate(&self, layout: Layout) -> Option>; unsafe fn deallocate(&self, pointer: NonNull, layout: Layout); unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option>; diff --git a/src/allocator/proxy.rs b/src/allocator/proxy.rs index 9628da89..57e52b0b 100644 --- a/src/allocator/proxy.rs +++ b/src/allocator/proxy.rs @@ -1,37 +1,87 @@ -use { - super::Allocator, - core::{ - alloc::Layout, - ptr::NonNull - } +use super::{ + Allocator, + requirement::Requirement +}; +#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] +use alloc::alloc::AllocError; +#[cfg(feature = "allocator-api2")] +use allocator_api2::alloc::AllocError; +#[cfg(feature = "allocator-api")] +use core::{ + alloc::Layout, + ptr::NonNull }; #[repr(transparent)] pub struct Proxy<'valid, Heap: Allocator>(pub &'valid Heap); -impl<'valid, Heap: Allocator> Allocator for Proxy<'valid, Heap> { +#[cfg(not(feature = "allocator-api"))] +impl<'valid, Heap: Allocator> Requirement for Proxy<'valid, Heap> {} +#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] +unsafe impl<'valid, Heap: Allocator> Requirement for Proxy<'valid, Heap> { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + Requirement::allocate(&self, layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + Requirement::deallocate(&self, ptr, layout); + } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout + ) -> Result, AllocError> { + unsafe { Requirement::grow(&self, ptr, old_layout, new_layout) } + } + #[inline] - fn allocate(&self, layout: Layout) -> Option> { - self.0.allocate(layout) + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout + ) -> Result, AllocError> { + unsafe { Requirement::shrink(&self, ptr, old_layout, new_layout) } + } +} +#[cfg(feature = "allocator-api2")] +unsafe impl<'valid, Heap: Allocator> Requirement for Proxy<'valid, Heap> { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + Requirement::allocate(&self, layout) } #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { self.0.deallocate(pointer, layout) }; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { + Requirement::deallocate(&self, ptr, layout); + } } #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - unsafe { self.0.grow(pointer, old, new) } + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout + ) -> Result, AllocError> { + unsafe { Requirement::grow(&self, ptr, old_layout, new_layout) } } #[inline] unsafe fn shrink( &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - unsafe { self.0.shrink(pointer, old, new) } + ptr: NonNull, + old_layout: Layout, + new_layout: Layout + ) -> Result, AllocError> { + unsafe { Requirement::shrink(&self, ptr, old_layout, new_layout) } } } diff --git a/src/allocator/requirement.rs b/src/allocator/requirement.rs index 23529e2c..2ba895b0 100644 --- a/src/allocator/requirement.rs +++ b/src/allocator/requirement.rs @@ -3,4 +3,4 @@ pub use alloc::alloc::Allocator as Requirement; #[cfg(feature = "allocator-api2")] pub use allocator_api2::alloc::Allocator as Requirement; #[cfg(not(feature = "allocator-api"))] -pub use core::marker::Sized as Requirement; +pub trait Requirement {} diff --git a/src/allocator/vec.rs b/src/allocator/vec.rs index a7801449..bd27302a 100644 --- a/src/allocator/vec.rs +++ b/src/allocator/vec.rs @@ -2,22 +2,164 @@ pub use alloc::vec; #[cfg(feature = "allocator-api2")] pub use allocator_api2::vec; +#[cfg(not(feature = "allocator-api2"))] +use core::mem::ManuallyDrop; use { super::{ Allocator, - like::Like, - requirement::Requirement + like::Like }, - core::marker::PhantomData + core::{ + marker::PhantomData, + mem::MaybeUninit, + num::NonZero, + ptr::{ + NonNull, + slice_from_raw_parts_mut + } + } }; -pub struct Vec(PhantomData<(Heap, Item)>); +pub struct Vec(PhantomData<(Heap, Item)>); -impl Like for Vec { +impl Like for Vec { + type Heap = Heap; + type Item = Item; #[cfg(not(feature = "allocator-api"))] type Type = alloc::vec::Vec; #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] type Type = alloc::vec::Vec; #[cfg(feature = "allocator-api2")] type Type = allocator_api2::vec::Vec; + + #[cfg(not(feature = "allocator-api"))] + fn destruct( + value: Self::Type + ) -> ( + Option]>>, + usize, + Self::Heap + ) { + let mut data = ManuallyDrop::new(value); + ( + NonZero::new(data.capacity()).and_then(|capacity| { + NonNull::new(slice_from_raw_parts_mut( + data.as_mut_ptr().cast(), + capacity.get() + )) + }), + data.len(), + #[allow(clippy::uninit_assumed_init)] + unsafe { + MaybeUninit::uninit().assume_init() + } + ) + } + + #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] + fn destruct( + mut value: Self::Type + ) -> ( + Option]>>, + usize, + Self::Heap + ) { + let (pointer, length, capacity, allocator) = value.into_raw_parts_with_allocator(); + ( + NonZero::new(capacity).and_then(|capacity| { + NonNull::new(slice_from_raw_parts_mut(pointer.cast(), capacity.get())) + }), + length, + allocator + ) + } + + #[cfg(feature = "allocator-api2")] + fn destruct( + value: Self::Type + ) -> ( + Option]>>, + usize, + Self::Heap + ) { + let (pointer, length, capacity, allocator) = value.into_raw_parts_with_alloc(); + ( + NonZero::new(capacity).and_then(|capacity| { + NonNull::new(slice_from_raw_parts_mut(pointer.cast(), capacity.get())) + }), + length, + allocator + ) + } + + #[cfg(not(feature = "allocator-api"))] + fn construct( + pointer: Option]>>, + length: usize, + _allocator: Self::Heap + ) -> Self::Type { + if let Some(pointer) = pointer { + unsafe { Self::Type::from_raw_parts(pointer.as_ptr().cast(), length, pointer.len()) } + } else { + let mut vector = Self::Type::new(); + if size_of::() == 0 { + // SAFETY: we can change the length freely as copying the item + // because it is a ZST + unsafe { vector.set_len(length) } + }; + vector + } + } + + #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] + fn construct( + pointer: Option]>>, + length: usize, + allocator: Self::Heap + ) -> Self::Type { + if let Some(pointer) = pointer { + unsafe { + Self::Type::from_raw_parts_in( + pointer.as_ptr().cast(), + length, + pointer.len(), + allocator + ) + } + } else { + let mut vector = Self::Type::new_in(allocator); + if size_of::() == 0 { + // SAFETY: we can change the length freely as copying the item + // because it is a ZST + unsafe { vector.set_len(length) } + }; + vector + } + } + + #[cfg(feature = "allocator-api2")] + fn construct( + pointer: Option]>>, + length: usize, + allocator: Self::Heap + ) -> Self::Type { + if let Some(pointer) = pointer { + unsafe { + Self::Type::from_raw_parts_in( + pointer.as_ptr().cast(), + length, + pointer.len(), + allocator + ) + } + } else { + let mut vector = Self::Type::new_in(allocator); + if size_of::() == 0 { + // SAFETY: we can change the length freely as copying the item + // because it is a ZST + unsafe { vector.set_len(length) } + }; + vector + } + } } diff --git a/src/conversions.rs b/src/conversions.rs index fd6a41f2..0b566367 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -25,23 +25,20 @@ use { impl From<&[Item]> for SmallVec { #[inline] fn from(slice: &[Item]) -> Self { - if slice.len() > Self::inline_size() { - // Standard Rust vectors are already specialized. - as Like>::Type::from(slice).into() - } else { - // SAFETY: The precondition is checked in the initial comparison - // above. + if slice.len() <= Self::inline_size() { + // SAFETY: The precondition is already checked above unsafe { #[cfg(feature = "specialization")] { >::spec_from(slice) } - #[cfg(not(feature = "specialization"))] { Self::from_slice_fallback(slice) } } + } else { + as Like>::Type::from(slice).into() } } } @@ -53,136 +50,108 @@ impl From<&mut [Item]> for SmallVec From<&[Item; M]> +impl From<&[Item; LENGTH]> for SmallVec { #[inline] - fn from(slice: &[Item; M]) -> Self { + fn from(slice: &[Item; LENGTH]) -> Self { Self::from(slice as &[Item]) } } -impl From<&mut [Item; M]> +impl From<&mut [Item; LENGTH]> for SmallVec { #[inline] - fn from(slice: &mut [Item; M]) -> Self { + fn from(slice: &mut [Item; LENGTH]) -> Self { Self::from(slice as &[Item]) } } -impl From<[Item; M]> for SmallVec { - fn from(array: [Item; M]) -> Self { - if M > INLINE { - // If M > INLINE, we'd have to heap allocate anyway, - // so delegate for Vec for the allocation. - Self::from( as Like>::Type::from(array)) +impl From<[Item; LENGTH]> + for SmallVec +{ + fn from(array: [Item; LENGTH]) -> Self { + if const { LENGTH > INLINE } { + as Like>::Type::from(array).into() } else { - // M <= INLINE - let mut this = Self::new(); - debug_assert!(M <= this.capacity()); - let array = ManuallyDrop::new(array); - // SAFETY: M <= this.capacity() + let mut smallvec = Self::new(); + let data = ManuallyDrop::new(array); + // SAFETY: LENGTH <= INLINE, thus it fits unsafe { - copy_nonoverlapping(array.as_ptr(), this.as_mut_ptr(), M); - this.set_len(M); + copy_nonoverlapping(data.as_ptr(), smallvec.as_mut_ptr(), LENGTH); + smallvec.set_len(LENGTH); } - this + smallvec } } } - -impl - TryFrom> for [Item; M] +impl + TryFrom> for [Item; LENGTH] { type Error = SmallVec; #[inline] fn try_from( - mut this: SmallVec - ) -> Result<[Item; M], SmallVec> { - if this.len() != M { - Err(this) - } else { - // SAFETY: we release ownership of the elements we hold - unsafe { - this.set_len(0); - } - let ptr = this.as_ptr() as *const [Item; M]; - // SAFETY: these elements are initialized since the length was `M` - unsafe { Ok(ptr.read()) } - } + mut smallvec: SmallVec + ) -> Result<[Item; LENGTH], SmallVec> { + // SAFETY: we release ownership of the elements we hold + (smallvec.len() == LENGTH) + .then(|| unsafe { + smallvec.set_len(0); + smallvec.as_ptr().cast::<[Item; LENGTH]>().read() + }) + .ok_or(smallvec) } } -impl From< as Like>::Type> - for SmallVec +impl From< as Like>::Type> + for SmallVec { - fn from(array: as Like>::Type) -> Self { - if array.capacity() == 0 { - return Self::new(); - } - + fn from(vec: as Like>::Type) -> Self { + let (pointer, length, allocator) = as Like>::destruct(vec); if Self::IS_ZST { - // "Move" elements to stack buffer. They're ZST so we don't actually - // have to do anything. Just make sure they're not - // dropped. We don't wrap the vector in ManuallyDrop so - // that when it's dropped, the memory is deallocated, if - // it needs to be. - let mut vec = array; - let length = vec.len(); - - // SAFETY: `0` is less than the vector's capacity. - // old_len..new_len is an empty range. So there are no uninitialized - // elements - unsafe { vec.set_len(0) }; Self { length: LocatedLength::new(length, false), raw: RawSmallVec::new(), - allocator: Global + allocator } - } else { - let mut vec = ManuallyDrop::new(array); - let length = vec.len(); - - // A heap-allocated `SmallVec` must always observe the invariant - // that `cap > INLINE`. - if vec.capacity() <= INLINE { - vec.reserve(INLINE + 1 - length); - } - let cap = vec.capacity(); - // SAFETY: vec.capacity is not `0` (checked above), so the pointer - // can not dangle and thus specifically cannot be null. - let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; - + } else if let Some(pointer) = pointer { Self { length: LocatedLength::new(length, true), - raw: RawSmallVec::heap(ptr, cap), - allocator: Global + raw: RawSmallVec::heap(pointer.cast(), pointer.len()), + allocator + } + } else { + Self { + length: LocatedLength::new(0, false), + raw: RawSmallVec::new(), + allocator } } } } - impl From> - for as Like>::Type + for as Like>::Type { - fn from(this: SmallVec) -> Self { - let (length, on_heap) = this.length.parts(); + fn from(smallvec: SmallVec) -> Self { + let (length, on_heap) = smallvec.length.parts(); + let smallvec = ManuallyDrop::new(smallvec); if !on_heap { - let mut vec = as Like>::Type::with_capacity(length); - let this = ManuallyDrop::new(this); + let mut vector = as Like>::construct(None, 0, unsafe { + (&raw const smallvec.allocator).read() + }); + vector.reserve(length); // SAFETY: we create a new vector with sufficient capacity, copy our // elements into it to transfer ownership and then set // the length we don't drop the elements we previously // held unsafe { - copy_nonoverlapping(this.raw.as_ptr_inline(), vec.as_mut_ptr(), length); - vec.set_len(length); + copy_nonoverlapping(smallvec.raw.as_ptr_inline(), vector.as_mut_ptr(), length); + vector.set_len(length); } - vec + vector } else { - let this = ManuallyDrop::new(this); // SAFETY: // - `ptr` was created with the SmallVec's allocator // - `ptr` was created with the appropriate alignment for `Item` @@ -191,23 +160,28 @@ impl From as Like>::Type::from_raw_parts(ptr.as_ptr(), length, cap) + let (ptr, cap) = smallvec.raw.heap; + Vec::construct( + Some(NonNull::slice_from_raw_parts(ptr.cast(), cap)), + length, + (&raw const smallvec.allocator).read() + ) } } } } impl From> - for as Like>::Type + for as Like>::Type { - fn from(this: SmallVec) -> Self { - as Like>::Type::from(this).into_boxed_slice() + fn from(smallvec: SmallVec) -> Self { + as Like>::Type::from(smallvec).into_boxed_slice() } } - -impl From< as Like>::Type> for SmallVec { - fn from(boxed: as Like>::Type) -> Self { +impl From< as Like>::Type> + for SmallVec +{ + fn from(boxed: as Like>::Type) -> Self { boxed.into_vec().into() } } diff --git a/src/lib.rs b/src/lib.rs index a4c18d43..53e9d7d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,12 @@ use proptest::{ Strategy } }; +#[cfg(any( + feature = "allocator-api", + feature = "internals", + feature = "may-dangle" +))] +use smallvec_macro::syntax; #[cfg(feature = "specialization")] use specialization::{ SpecCloneFrom, @@ -131,8 +137,7 @@ use { from_raw_parts_mut } }, - newrange::NewRange, - smallvec_macro::syntax + newrange::NewRange }; pub use { error::SmallVecError, @@ -1004,13 +1009,13 @@ impl SmallVec { #[inline] #[deprecated(since = "2.0.0", note = "use `Into::>::into` instead")] - pub fn into_vec(self) -> as Like>::Type { + pub fn into_vec(self) -> as Like>::Type { self.into() } #[inline] #[deprecated(since = "2.0.0", note = "use `Into::>::into` instead")] - pub fn into_boxed_slice(self) -> as Like>::Type { + pub fn into_boxed_slice(self) -> as Like>::Type { self.into() }