#array-vec #non-empty #slice #testing #repr #transparent #convert

no-std nunny

the definitive non-empty slice/array/vec library for Rust

8 releases

0.2.1 Apr 30, 2024
0.2.0 Apr 30, 2024
0.1.4 Apr 30, 2024
0.0.0 Apr 24, 2024

#235 in Rust patterns

Download history 1097/week @ 2024-07-20 594/week @ 2024-07-27 1167/week @ 2024-08-03 928/week @ 2024-08-10 1618/week @ 2024-08-17 1216/week @ 2024-08-24 2060/week @ 2024-08-31 1592/week @ 2024-09-07 1052/week @ 2024-09-14 1700/week @ 2024-09-21 1463/week @ 2024-09-28 1245/week @ 2024-10-05 1209/week @ 2024-10-12 718/week @ 2024-10-19 999/week @ 2024-10-26 777/week @ 2024-11-02

3,904 downloads per month
Used in 3 crates

MIT/Apache

200KB
2.5K SLoC

The definitive non-empty slice/array/vec library for Rust.

Features

Nonempty-by-construction API

let mut my_vec = NonEmpty::<Vec<_>>::of("hello"); // construct once
my_vec.push("world");                             // continue using your normal APIs
let hello: &str = my_vec.first();                 // preserve the guarantee that there is at least one element

#[repr(transparent)] allows advanced usecases and guarantees optimum performance[^1]:

let src = &mut ["hello", "world"];
let ne = NonEmpty::<[_]>::new_mut(src).unwrap();
//  ^ uses the same backing memory
let world: &str = ne.last();

Total API coverage. For every impl of From, TryFrom, PartialEq and PartialOrd in [std][^2], there is a corresponding impl in this library for Slice, Array and [Vec]. This includes more exotic types:

let nun: Box<NonEmpty<[_]>> = vec![0xDEAD, 0xBEEF].into();
let cow: Cow<NonEmpty<[_]>> = (&*nun).into();
let arc: Arc<NonEmpty<[_]>> = cow.into_owned().into();

const-friendly API. Where possible, all methods are const.

const TWO: &NonEmpty<[&str]> = slice!["together", "forever"];
const FIRST: &str = TWO.first();
const ONE: &NonEmpty<[&str]> = NonEmpty::<[_]>::of(&"lonely");

Extensive feature gating supporting:

  • no-std environments with no allocator.
  • alloc-enabled environments.
  • full-std-enabled environments.
  • interaction with crates like serde and arbitrary.

Iterator support: Specialized Iterator methods remove branches to handle empty iterators, and preserve invariants even when chaining combinators.

let v = vec![1, 2, 3];
let _: Option<&u8> = v.iter().last();
    // ^ normally you have to handle the empty case
let _: &u8 = v.iter_ne().last();
    // ^ but we know there is at least one element
let _: u8 = v.iter_ne().copied().last();
                     // ^ using this combinator preserves the invariant

Thoughtful design:

[^1]: Other crates like nonempty require an indirection. [^2]: Barring impls on !#[fundamental] types like Arc. Fun fact: our tests were generated from [std]'s rustdoc!

Dependencies

~0–1MB
~18K SLoC