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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
//! A vector type that is statically guaranteed to be non-empty
//!
//! In situations where a vector is known to have at least 1 element, this
//! data structure enables writing code without calls to `Vec::unwrap`. That is,
//! it provides a way to statically enforce the invariant.
use std::ops::Index;
/// Non-empty vector type.
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Nevec<T> {
first: T,
tail: Vec<T>,
}
impl<T> Nevec<T> {
/// Creates a new `Nevec` with the provided first element.
pub fn new(first: T) -> Nevec<T> {
Nevec::<T>::new_with_tail(first, Vec::new())
}
/// Creates a new `Nevec` with the provided first element and initial capacity.
pub fn with_capacity(first: T, capacity: usize) -> Nevec<T> {
Nevec::<T>::new_with_tail(first, Vec::with_capacity(capacity))
}
/// Creates a new `Nevec` with the provided first element and remaining elements ("the tail").
pub fn new_with_tail(first: T, tail: Vec<T>) -> Nevec<T> {
Nevec { first, tail }
}
/// Gets a reference to the last element of the vector.
/// Because the vector is guaranteed to be non-empty, this will always succeed.
pub fn last(&self) -> &T {
match self.tail.last() {
None => &self.first,
Some(t) => t,
}
}
/// Gets a mutable reference to the last element of the vector.
/// Because the vector is guaranteed to be non-empty, this will always succeed.
pub fn last_mut(&mut self) -> &mut T {
match self.tail.last_mut() {
None => &mut self.first,
Some(t) => t,
}
}
/// Pushes an element onto the end of the vector.
pub fn push(&mut self, t: T) {
self.tail.push(t)
}
/// Pops an element from the end of the vector.
///
/// Because the vector is guaranteed to be non-empty, this will always succeed.
/// However if the vector has only 1 element, then after popping it will no longer
/// be non-empty. For this reason, the pop method takes ownership of the vector,
/// and destroys it in the process.
///
/// In the case when the vector has more than 1 element, the method `pop_from_tail`
/// can be used to retrieve the last element without destroying the vector.
pub fn pop(mut self) -> T {
match self.tail.pop() {
None => self.first,
Some(t) => t,
}
}
/// Pops an element from the tail of the vector; that is, the part of the vector
/// after the first element.
///
/// Returns `None` if and only if the vector has exactly 1 element. In this
/// case the method `pop` is needed to take ownership of the element.
pub fn pop_from_tail(&mut self) -> Option<T> {
self.tail.pop()
}
/// Returns the length of the vector, which is guaranteed to be at least 1.
pub fn len(&self) -> usize {
1 + self.tail.len()
}
/// Returns whether the vector is non-empty, which it always is.
pub fn is_empty(&self) -> bool {
true
}
/// Get a reference to the element at the provided index.
pub fn get(&self, i: usize) -> Option<&T> {
if i == 0 {
return Some(&self.first);
}
self.tail.get(i - 1)
}
/// Get a mutable reference to the element at the provided index.
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
if i == 0 {
return Some(&mut self.first);
}
self.tail.get_mut(i - 1)
}
}
impl<T> Index<usize> for Nevec<T> {
type Output = T;
fn index(&self, i: usize) -> &Self::Output {
if i == 0 {
&self.first
} else {
&self.tail[i - 1]
}
}
}
impl<'a, T> IntoIterator for &'a Nevec<T> {
type Item = &'a T;
type IntoIter = NevecIter<'a, T>;
fn into_iter(self) -> NevecIter<'a, T> {
NevecIter { vec: self, i: 0 }
}
}
impl<T: std::fmt::Display> std::fmt::Display for Nevec<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for t in self {
write![f, "{t}"]?;
}
Ok(())
}
}
pub struct NevecIter<'a, T> {
vec: &'a Nevec<T>,
i: usize,
}
impl<'a, T> Iterator for NevecIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.i >= self.vec.len() {
None
} else {
self.i += 1;
Some(&self.vec[self.i - 1])
}
}
}
/// Create a new [Nevec] (non-empty vector).
#[macro_export]
macro_rules! nevec {
( $first: expr, $ ( $ x : expr ) , * ) => (
Nevec::new_with_tail($first, vec![$ ( $ x ) , *])
);
( $first: expr, $ ( $ x : expr , ) * ) => ( nevec ! [ $first, $ ( $ x ) , * ] );
( $first: expr ) => {
Nevec::new($first)
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn singleton_vector() {
let mut v = nevec![3];
assert_eq![v.len(), 1];
assert_eq![v.last(), &3];
assert_eq![v.last_mut(), &3];
assert_eq![v.pop_from_tail(), None];
assert_eq![v.pop(), 3];
}
#[test]
fn two_element_vector() {
let mut v = nevec![3, 4];
assert_eq![v.len(), 2];
assert_eq![v.last(), &4];
assert_eq![v.last_mut(), &4];
assert_eq![v[0], 3];
assert_eq![v[1], 4];
assert_eq![v.pop_from_tail(), Some(4)];
assert_eq![v.last(), &3];
assert_eq![v.last_mut(), &3];
assert_eq![v.pop_from_tail(), None];
}
#[test]
fn vector_with_push() {
let mut v = nevec![3, 4,];
assert_eq![v.len(), 2];
v.push(5);
assert_eq![v.len(), 3];
assert_eq![v.last(), &5];
assert_eq![v.last_mut(), &5];
assert_eq![v.pop_from_tail(), Some(5)];
}
#[test]
fn other_macro_constructor_case() {
let mut v = nevec![3,];
assert_eq![v.len(), 1];
assert_eq![v.last(), &3];
assert_eq![v.last_mut(), &3];
assert_eq![v.pop_from_tail(), None];
assert_eq![v.pop(), 3];
}
}