Skip to content

Commit 11e34ee

Browse files
committed
feat: const_new feature allows const init of items + docs
1 parent 7bf1291 commit 11e34ee

File tree

3 files changed

+99
-7
lines changed

3 files changed

+99
-7
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ documentation = "https://docs.rs/smallvec/"
1313

1414
[features]
1515
const_generics = []
16-
const_new = []
16+
const_new = ["const_generics"]
1717
write = []
1818
union = []
1919
specialization = []
@@ -24,3 +24,7 @@ serde = { version = "1", optional = true, default-features = false }
2424

2525
[dev_dependencies]
2626
bincode = "1.0.1"
27+
28+
[package.metadata.docs.rs]
29+
all-features = true
30+
rustdoc-args = ["--cfg", "docsrs"]

src/lib.rs

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@
7272
//!
7373
//! **This feature is unstable and requires a nightly build of the Rust toolchain.**
7474
//!
75-
//! This feature exposes the function [`SmallVec::new_const`] which is a `const fn` so the `SmallVec` may be used from a const context.
75+
//! This feature exposes the functions [`SmallVec::new_const`] and [`SmallVec::from_const`] which enables the `SmallVec` to be initialized from a const context.
7676
//! For details, see the
7777
//! [Rust Reference](https://doc.rust-lang.org/reference/const_eval.html#const-functions).
7878
//!
7979
//! Tracking issue: [rust-lang/rust#57563](https://github.com/rust-lang/rust/issues/57563)
8080
8181
#![no_std]
82+
#![cfg_attr(docsrs, feature(doc_cfg))]
8283
#![cfg_attr(feature = "specialization", allow(incomplete_features))]
8384
#![cfg_attr(feature = "specialization", feature(specialization))]
8485
#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))]
@@ -181,6 +182,53 @@ macro_rules! smallvec {
181182
});
182183
}
183184

185+
186+
/// Creates an inline [`SmallVec`] containing the arguments. This macro is enabled by the feature `const_new`.
187+
///
188+
/// `smallvec_inline!` allows `SmallVec`s to be defined with the same syntax as array expressions in `const` contexts.
189+
/// The inline storage `A` will always be an array of the size specified by the arguments.
190+
/// There are two forms of this macro:
191+
///
192+
/// - Create a [`SmallVec`] containing a given list of elements:
193+
///
194+
/// ```
195+
/// # #[macro_use] extern crate smallvec;
196+
/// # use smallvec::SmallVec;
197+
/// # fn main() {
198+
/// const V: SmallVec<[i32; 3]> = smallvec_inline![1, 2, 3];
199+
/// assert_eq!(V[0], 1);
200+
/// assert_eq!(V[1], 2);
201+
/// assert_eq!(V[2], 3);
202+
/// # }
203+
/// ```
204+
///
205+
/// - Create a [`SmallVec`] from a given element and size:
206+
///
207+
/// ```
208+
/// # #[macro_use] extern crate smallvec;
209+
/// # use smallvec::SmallVec;
210+
/// # fn main() {
211+
/// const V: SmallVec<[i32; 3]> = smallvec_inline![1; 3];
212+
/// assert_eq!(V, SmallVec::from_buf([1, 1, 1]));
213+
/// # }
214+
/// ```
215+
///
216+
/// Note that the behavior mimics that of array expressions, in contrast to [`smallvec`].
217+
#[cfg(feature = "const_new")]
218+
#[cfg_attr(docsrs, doc(cfg(feature = "const_new")))]
219+
#[macro_export]
220+
macro_rules! smallvec_inline {
221+
// count helper: transform any expression into 1
222+
(@one $x:expr) => (1usize);
223+
($elem:expr; $n:expr) => ({
224+
$crate::SmallVec::<[_; $n]>::from_const([$elem; $n])
225+
});
226+
($($x:expr),+ $(,)?) => ({
227+
const N: usize = 0usize $(+ $crate::smallvec_inline!(@one $x))*;
228+
$crate::SmallVec::<[_; N]>::from_const([$($x,)*])
229+
});
230+
}
231+
184232
/// `panic!()` in debug builds, optimization hint in release.
185233
#[cfg(not(feature = "union"))]
186234
macro_rules! debug_unreachable {
@@ -366,6 +414,7 @@ union SmallVecData<A: Array> {
366414

367415
#[cfg(all(feature = "union", feature = "const_new"))]
368416
impl<A: Array> SmallVecData<A> {
417+
#[cfg_attr(docsrs, doc(cfg(feature = "const_new")))]
369418
#[inline]
370419
const fn from_const(inline: MaybeUninit<A>) -> SmallVecData<A> {
371420
SmallVecData {
@@ -416,6 +465,7 @@ enum SmallVecData<A: Array> {
416465

417466
#[cfg(all(not(feature = "union"), feature = "const_new"))]
418467
impl<A: Array> SmallVecData<A> {
468+
#[cfg_attr(docsrs, doc(cfg(feature = "const_new")))]
419469
#[inline]
420470
const fn from_const(inline: MaybeUninit<A>) -> SmallVecData<A> {
421471
SmallVecData::Inline(inline)
@@ -1360,7 +1410,7 @@ impl<A: Array> SmallVec<A> {
13601410

13611411
#[cfg(feature = "const_new")]
13621412
impl<A: Array> SmallVec<A> {
1363-
/// Construct an empty vector.
1413+
/// Construct an empty vector. This is currently gated behind the feature `const_new`.
13641414
///
13651415
/// # Safety
13661416
/// No size validation is attempted for this function.
@@ -1369,6 +1419,7 @@ impl<A: Array> SmallVec<A> {
13691419
///
13701420
/// [`Array`]: crate::Array
13711421
/// [`new`]: crate::SmallVec::new
1422+
#[cfg_attr(docsrs, doc(cfg(feature = "const_new")))]
13721423
#[inline]
13731424
pub const unsafe fn new_const() -> SmallVec<A> {
13741425
SmallVec {
@@ -1536,6 +1587,7 @@ impl<A: Array> BorrowMut<[A::Item]> for SmallVec<A> {
15361587
}
15371588

15381589
#[cfg(feature = "write")]
1590+
#[cfg_attr(docsrs, doc(cfg(feature = "write")))]
15391591
impl<A: Array<Item = u8>> io::Write for SmallVec<A> {
15401592
#[inline]
15411593
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -1556,6 +1608,7 @@ impl<A: Array<Item = u8>> io::Write for SmallVec<A> {
15561608
}
15571609

15581610
#[cfg(feature = "serde")]
1611+
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
15591612
impl<A: Array> Serialize for SmallVec<A>
15601613
where
15611614
A::Item: Serialize,
@@ -1570,6 +1623,7 @@ where
15701623
}
15711624

15721625
#[cfg(feature = "serde")]
1626+
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
15731627
impl<'de, A: Array> Deserialize<'de> for SmallVec<A>
15741628
where
15751629
A::Item: Deserialize<'de>,
@@ -1999,15 +2053,30 @@ impl<'a> Drop for SetLenOnDrop<'a> {
19992053
}
20002054
}
20012055

2002-
#[cfg(feature = "const_generics")]
2056+
#[cfg(feature = "const_new")]
2057+
impl<T, const N: usize> SmallVec<[T; N]> {
2058+
/// The array passed as an argument is moved to be an inline version of `SmallVec`.
2059+
/// This is a `const` version of [`SmallVec::from_buf`] that is enabled by the feature `const_new`, with the limitation that it only works for arrays.
2060+
#[cfg_attr(docsrs, doc(cfg(feature = "const_new")))]
2061+
#[inline]
2062+
pub const fn from_const(items: [T; N]) -> SmallVec<[T; N]> {
2063+
SmallVec {
2064+
capacity: N,
2065+
data: SmallVecData::from_const(MaybeUninit::new(items)),
2066+
}
2067+
}
2068+
}
2069+
2070+
#[cfg(all(feature = "const_generics", not(doc)))]
2071+
#[cfg_attr(docsrs, doc(cfg(feature = "const_generics")))]
20032072
unsafe impl<T, const N: usize> Array for [T; N] {
20042073
type Item = T;
20052074
fn size() -> usize {
20062075
N
20072076
}
20082077
}
20092078

2010-
#[cfg(not(feature = "const_generics"))]
2079+
#[cfg(any(not(feature = "const_generics"), doc))]
20112080
macro_rules! impl_array(
20122081
($($size:expr),+) => {
20132082
$(
@@ -2019,7 +2088,7 @@ macro_rules! impl_array(
20192088
}
20202089
);
20212090

2022-
#[cfg(not(feature = "const_generics"))]
2091+
#[cfg(any(not(feature = "const_generics"), doc))]
20232092
impl_array!(
20242093
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
20252094
26, 27, 28, 29, 30, 31, 32, 36, 0x40, 0x60, 0x80, 0x100, 0x200, 0x400, 0x600, 0x800, 0x1000,

src/tests.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,12 +906,31 @@ fn const_generics() {
906906
#[cfg(feature = "const_new")]
907907
#[test]
908908
fn const_new() {
909-
let _v = const_new_inner();
909+
let v = const_new_inner();
910+
assert_eq!(v.capacity(), 4);
911+
assert_eq!(v.len(), 0);
912+
let v = const_new_inline_sized();
913+
assert_eq!(v.capacity(), 4);
914+
assert_eq!(v.len(), 4);
915+
assert_eq!(v[0], 1);
916+
let v = const_new_inline_args();
917+
assert_eq!(v.capacity(), 2);
918+
assert_eq!(v.len(), 2);
919+
assert_eq!(v[0], 1);
920+
assert_eq!(v[1], 4);
910921
}
911922
#[cfg(feature = "const_new")]
912923
const fn const_new_inner() -> SmallVec<[i32; 4]> {
913924
unsafe { SmallVec::<[i32; 4]>::new_const() }
914925
}
926+
#[cfg(feature = "const_new")]
927+
const fn const_new_inline_sized() -> SmallVec<[i32; 4]> {
928+
crate::smallvec_inline![1; 4]
929+
}
930+
#[cfg(feature = "const_new")]
931+
const fn const_new_inline_args() -> SmallVec<[i32; 2]> {
932+
crate::smallvec_inline![1, 4]
933+
}
915934

916935
#[test]
917936
fn empty_macro() {

0 commit comments

Comments
 (0)