Correct by Construction Non-Empty List
This package exposes a type NonEmpty<T>
with a data representation that guarantees non-emptiness statically:
struct NonEmpty<T>(T, Vec<T>)
The library is meant to have an interface similar to std::vec::Vec
:
use nonempty::NonEmpty;
let mut l = NonEmpty::new(42);
assert_eq!(l.first(), &42);
l.push(36);
l.push(58);
let v: Vec<i32> = l.into();
assert_eq!(v, vec![42, 36, 58]);
lib.rs
:A Non-empty growable vector.
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 as 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 NonEmpty
, 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
, NonEmpty::first
and NonEmpty::last
don't return in Option
, they always succeed.
Examples
The simplest way to construct a NonEmpty
is via the nonempty
macro:
use nonempty::{NonEmpty, nonempty};
let l: NonEmpty<u32> = nonempty![1, 2, 3];
assert_eq!(l.head, 1);
Unlike the familiar vec!
macro, nonempty!
requires at least one element:
use nonempty::nonempty;
let l = nonempty![1];
// Doesn't compile!
// let l = nonempty![];
Like Vec
, you can also construct a NonEmpty
the old fashioned way with NonEmpty::new
or its constructor:
use nonempty::NonEmpty;
let mut l = NonEmpty { head: 42, tail: vec![36, 58] };
assert_eq!(l.head, 42);
l.push(9001);
assert_eq!(l.last(), &9001);
And if necessary, you're free to convert to and from Vec
:
use nonempty::{NonEmpty, nonempty};
let l: NonEmpty<u32> = nonempty![42, 36, 58, 9001];
let v: Vec<u32> = l.into();
assert_eq!(v, vec![42, 36, 58, 9001]);
let u: Option<NonEmpty<u32>> = NonEmpty::from_vec(v);
assert_eq!(Some(nonempty![42, 36, 58, 9001]), u);
Caveats
Since NonEmpty
must have a least one element, it is not possible to implement the FromInterator
trait for it. We can't know, in general, if any given Iterator
actually contains something.
Features
serialize
: serde
support.Author: cloudhead
Source: https://github.com/cloudhead/nonempty
License: MIT license