Correct-by-Construction Collections
Non-empty variants of the standard collections.
Non-emptiness can be a powerful guarantee. If your main use of Vec
is as
an Iterator
, then you may not need to distinguish on emptiness. But there
are indeed times when the Vec
you receive as a function argument needs to
be non-empty or your function can't proceed. Similarly, there are times when
the Vec
you return to a calling user needs to promise it actually contains
something.
With NEVec
, you're freed from the boilerplate of constantly needing to
check is_empty()
or pattern matching before proceeding, or erroring if you
can't. So overall, code, type signatures, and logic become cleaner.
Consider that unlike Vec
, [NEVec::first()
] and [NEVec::last()
] don't
return in Option
; they always succeed.
Alongside NEVec
are its cousins
NESlice
, NEMap
, and
NESet
, which are all guaranteed to contain at least
one item.
Examples
The simplest way to construct these non-empty collections is via their
macros: [nev!
], [nes!
], and [nem!
]:
use *;
let v: = nev!;
let s: = nes!; // 1 2 3
let m: = nem!;
assert_eq!;
assert_eq!;
assert!;
Unlike the familiar vec!
macro, nev!
and friends require at least one
element:
use nev;
let v = nev!;
A value must be provided:
let v = nev!; // Doesn't compile!
Like Vec
, you can also construct a NEVec
the old
fashioned way with [NEVec::new()
] or its constructor:
use NEVec;
let mut l = try_from_vec.unwrap;
assert_eq!;
l.push;
assert_eq!;
And if necessary, you're free to convert to and from Vec
:
use nev;
use NEVec;
let l: = nev!;
let v: = l.into;
assert_eq!;
let u: = try_from_vec;
assert_eq!;
Iterators
This library extends the notion of non-emptiness to iterators, and provides
the NonEmptyIterator
trait. This has some
interesting consequences:
- Functions like
map
preserve non-emptiness. - Functions like
max
always have a result. - A non-empty iterator chain can be
collect
ed back into a non-empty structure. - You can chain many operations together without having to double-check for emptiness.
use *;
let v: = nev!.into_nonempty_iter.map.collect;
assert_eq!;
Consider also [IntoIteratorExt::try_into_nonempty_iter
] for converting any
given [Iterator
] and [IntoIterator
] into a non-empty one, if it contains
at least one item.
Arrays
Since fixed-size arrays are by definition already not empty, they aren't
given a special wrapper type like NEVec
. Instead,
we enable them to be easily iterated over in a compatible way:
use *;
let a: = ;
let v: = a.into_nonempty_iter.map.collect;
assert_eq!;
See NonEmptyArrayExt
for more
conversions.
Caveats
Since NEVec
, NEMap
, and NESet
must have a least one element, it is not
possible to implement the [FromIterator
] trait for them. We can't
know, in general, if any given standard-library [Iterator
] actually
contains something.
Features
serde
:serde
support.indexmap
: addsNEIndexMap
a non-emptyIndexMap
.itertools
: addsNonEmptyItertools
a non-empty variant ofitertools
.either
: addsNEEither
a non-empty variant ofEither
from theeither
crate.