diff --git a/Cargo.toml b/Cargo.toml index b19b93e..ff39340 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ documentation = "https://docs.rs/smallvec/" [features] const_generics = [] +const_new = [] write = [] union = [] specialization = [] diff --git a/src/lib.rs b/src/lib.rs index 2e22a18..70129d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,11 +67,22 @@ //! [Rustonomicon](https://doc.rust-lang.org/1.42.0/nomicon/dropck.html#an-escape-hatch). //! //! Tracking issue: [rust-lang/rust#34761](https://github.com/rust-lang/rust/issues/34761) +//! +//! ### `const_new` +//! +//! **This feature is unstable and requires a nightly build of the Rust toolchain.** +//! +//! This feature exposes the function [`SmallVec::const_new`] which is a `const fn` so the `SmallVec` may be used from a const context. +//! For details, see the +//! [Rust Reference](https://doc.rust-lang.org/reference/const_eval.html#const-functions). +//! +//! Tracking issue: [rust-lang/rust#57563](https://github.com/rust-lang/rust/issues/57563) #![no_std] #![cfg_attr(feature = "specialization", allow(incomplete_features))] #![cfg_attr(feature = "specialization", feature(specialization))] #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] +#![cfg_attr(feature = "const_new", feature(const_fn_trait_bound))] #![deny(missing_docs)] #[doc(hidden)] @@ -353,6 +364,16 @@ union SmallVecData { heap: (*mut A::Item, usize), } +#[cfg(all(feature = "union", feature = "const_new"))] +impl SmallVecData { + #[inline] + const fn from_const(inline: MaybeUninit) -> SmallVecData { + SmallVecData { + inline: core::mem::ManuallyDrop::new(inline), + } + } +} + #[cfg(feature = "union")] impl SmallVecData { #[inline] @@ -393,6 +414,14 @@ enum SmallVecData { Heap((*mut A::Item, usize)), } +#[cfg(all(not(feature = "union"), feature = "const_new"))] +impl SmallVecData { + #[inline] + const fn from_const(inline: MaybeUninit) -> SmallVecData { + SmallVecData::Inline(inline) + } +} + #[cfg(not(feature = "union"))] impl SmallVecData { #[inline] @@ -1329,6 +1358,26 @@ impl SmallVec { } } +#[cfg(feature = "const_new")] +impl SmallVec { + /// Construct an empty vector. + /// + /// # Safety + /// No size validation is attempted for this function. + /// Invalid custom implementations of [`Array`] normally panics during [`new`]. + /// `new_const` will still initialize which may cause undefined behavior (such as segmentation errors) when used with invalid implementations. + /// + /// [`Array`]: crate::Array + /// [`new`]: crate::SmallVec::new + #[inline] + pub const unsafe fn new_const() -> SmallVec { + SmallVec { + capacity: 0, + data: SmallVecData::from_const(MaybeUninit::uninit()), + } + } +} + impl SmallVec where A::Item: Copy, diff --git a/src/tests.rs b/src/tests.rs index f30dfa2..a7c3fa6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -903,6 +903,16 @@ fn const_generics() { let _v = SmallVec::<[i32; 987]>::default(); } +#[cfg(feature = "const_new")] +#[test] +fn const_new() { + let _v = const_new_inner(); +} +#[cfg(feature = "const_new")] +const fn const_new_inner() -> SmallVec<[i32; 4]> { + unsafe { SmallVec::<[i32; 4]>::new_const() } +} + #[test] fn empty_macro() { let _v: SmallVec<[u8; 1]> = smallvec![];