From 39991edfa34502435b27de36937606cf98ebb16d Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 17 Mar 2026 15:02:07 -0700 Subject: [PATCH 1/3] add new_with_capacity constructor --- src/lib.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 07465bb..f0ed8b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,6 +221,72 @@ impl NonEmpty { Self::singleton(e) } + /// Constructs a new `NonEmpty` with at least the specified capacity. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is one, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// minimum *capacity* specified, the vector will have a zero *length*. For + /// an explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// If it is important to know the exact allocated capacity of a `Vec`, + /// always use the [`capacity`] method after construction. + /// + /// For `NonEmpty` where `T` is a zero-sized type, there will be no allocation + /// and the capacity will always be `usize::MAX`. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// [`capacity`]: Vec::capacity + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Errors + /// + /// With return Err if `capacity` is 0. + /// + /// # Examples + /// + /// ``` + /// let mut vec = NonEmpty::new_with_capacity(1, 10).unwrap(); + /// + /// // The vector contains one item, even though it has capacity for more + /// assert_eq!(vec.len(), 1); + /// assert!(vec.capacity().get() >= 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity().get() >= 11); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 12); + /// assert!(vec.capacity().get() >= 12); + /// + /// // A vector of a zero-sized type will always over-allocate, since no + /// // allocation is necessary + /// let vec_units = NonEmpty::<()>::new_with_capacity((), 10).unwrap(); + /// assert_eq!(vec_units.capacity(), NonZeroUsize::MAX); + /// ``` + #[inline] + #[must_use] + pub fn new_with_capacity(head: T, capacity: usize) -> Result { + if capacity == 0 { + return Err("capacity must be at least 1"); + } + Ok(Self { + head, + tail: Vec::with_capacity(capacity), + }) + } + /// Converts from `&NonEmpty` to `NonEmpty<&T>`. pub fn as_ref(&self) -> NonEmpty<&T> { NonEmpty { @@ -423,7 +489,7 @@ impl NonEmpty { /// assert_eq!(l_iter.next(), Some(&58)); /// assert_eq!(l_iter.next(), None); /// ``` - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { head: Some(&self.head), tail: &self.tail, @@ -1091,6 +1157,7 @@ pub mod serialize { #[cfg(test)] mod tests { use alloc::{string::String, vec::Vec}; + use core::num::NonZeroUsize; use crate::NonEmpty; @@ -1104,6 +1171,31 @@ mod tests { assert_eq!(result, expected); } + #[test] + fn test_new_with_capacity() { + let wrong_capacity = NonEmpty::new_with_capacity(1, 0); + assert!(wrong_capacity.is_err()); + + let mut vec = NonEmpty::new_with_capacity(1, 10).unwrap(); + + assert_eq!(vec.len(), 1); + assert!(vec.capacity().get() >= 10); + + for i in 0..10 { + vec.push(i); + } + + assert_eq!(vec.len(), 11); + assert!(vec.capacity().get() >= 11); + + vec.push(11); + assert_eq!(vec.len(), 12); + assert!(vec.capacity().get() >= 12); + + let vec_units = NonEmpty::<()>::new_with_capacity((), 10).unwrap(); + assert_eq!(vec_units.capacity(), NonZeroUsize::MAX); + } + #[test] fn test_into_iter() { let nonempty = NonEmpty::from((0, vec![1, 2, 3])); From 9c9cc98b91e822974e70af5bde7fc55612bc2b53 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 17 Mar 2026 16:10:41 -0700 Subject: [PATCH 2/3] use NonZeroUsize --- src/lib.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f0ed8b0..ab5c635 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -252,7 +252,7 @@ impl NonEmpty { /// # Examples /// /// ``` - /// let mut vec = NonEmpty::new_with_capacity(1, 10).unwrap(); + /// let mut vec = NonEmpty::new_with_capacity(1, NonZeroUsize::new(10).unwrap()); /// /// // The vector contains one item, even though it has capacity for more /// assert_eq!(vec.len(), 1); @@ -272,19 +272,16 @@ impl NonEmpty { /// /// // A vector of a zero-sized type will always over-allocate, since no /// // allocation is necessary - /// let vec_units = NonEmpty::<()>::new_with_capacity((), 10).unwrap(); + /// let vec_units = NonEmpty::<()>::new_with_capacity((), NonZeroUsize::new(10).unwrap()); /// assert_eq!(vec_units.capacity(), NonZeroUsize::MAX); /// ``` #[inline] #[must_use] - pub fn new_with_capacity(head: T, capacity: usize) -> Result { - if capacity == 0 { - return Err("capacity must be at least 1"); - } - Ok(Self { + pub fn new_with_capacity(head: T, capacity: NonZeroUsize) -> Self { + Self { head, - tail: Vec::with_capacity(capacity), - }) + tail: Vec::with_capacity(capacity.get() - 1), + } } /// Converts from `&NonEmpty` to `NonEmpty<&T>`. @@ -1173,26 +1170,25 @@ mod tests { #[test] fn test_new_with_capacity() { - let wrong_capacity = NonEmpty::new_with_capacity(1, 0); - assert!(wrong_capacity.is_err()); - - let mut vec = NonEmpty::new_with_capacity(1, 10).unwrap(); + let nz_10 = NonZeroUsize::new(10).unwrap(); + let mut vec = NonEmpty::new_with_capacity(1, nz_10); assert_eq!(vec.len(), 1); - assert!(vec.capacity().get() >= 10); + assert!(vec.capacity() >= nz_10); for i in 0..10 { vec.push(i); } - + let nz_11 = nz_10.saturating_add(1); assert_eq!(vec.len(), 11); - assert!(vec.capacity().get() >= 11); + assert!(vec.capacity() >= nz_11); + let nz_12 = nz_11.saturating_add(1); vec.push(11); assert_eq!(vec.len(), 12); - assert!(vec.capacity().get() >= 12); + assert!(vec.capacity() >= nz_12); - let vec_units = NonEmpty::<()>::new_with_capacity((), 10).unwrap(); + let vec_units = NonEmpty::<()>::new_with_capacity((), nz_10); assert_eq!(vec_units.capacity(), NonZeroUsize::MAX); } From 194326df8225f20f50d91d7591b5a40049ddbfe1 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 17 Mar 2026 21:00:16 -0700 Subject: [PATCH 3/3] fix comment --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ab5c635..943381d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -232,7 +232,7 @@ impl NonEmpty { /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// - /// If it is important to know the exact allocated capacity of a `Vec`, + /// If it is important to know the exact allocated capacity of a `NonEmpty`, /// always use the [`capacity`] method after construction. /// /// For `NonEmpty` where `T` is a zero-sized type, there will be no allocation