Skip to main content

graphcal_compiler/syntax/
non_empty.rs

1//! Small semantic helper for homogeneous non-empty sequences.
2//!
3//! Use this only when the domain means “one or more items” and neither end of
4//! the sequence has a distinct semantic role. If the head or tail is special
5//! (for example `qualifier + member`), prefer a domain-specific type instead.
6
7use std::ops::{Index, IndexMut};
8
9use thiserror::Error;
10
11/// A homogeneous sequence with at least one element.
12///
13/// The invariant is enforced at construction boundaries while the storage stays
14/// vector-backed. That keeps recursive AST shapes such as `NonEmpty<Expr<P>>`
15/// safely indirect, just like `Vec<Expr<P>>`.
16#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub struct NonEmpty<T> {
18    items: Vec<T>,
19}
20
21/// Error returned when converting an empty `Vec` into [`NonEmpty`].
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
23#[error("expected at least one item, got an empty vector")]
24pub struct EmptyVecError;
25
26impl<T> NonEmpty<T> {
27    /// Construct a non-empty sequence from its first item and the remaining items.
28    #[must_use]
29    pub fn new(first: T, rest: Vec<T>) -> Self {
30        let mut items = Vec::with_capacity(1 + rest.len());
31        items.push(first);
32        items.extend(rest);
33        Self { items }
34    }
35
36    /// Construct a singleton non-empty sequence.
37    #[must_use]
38    pub fn singleton(first: T) -> Self {
39        Self { items: vec![first] }
40    }
41
42    /// Convert a vector into a non-empty sequence.
43    ///
44    /// # Errors
45    ///
46    /// Returns [`EmptyVecError`] if `items` is empty.
47    pub fn try_from_vec(items: Vec<T>) -> Result<Self, EmptyVecError> {
48        if items.is_empty() {
49            Err(EmptyVecError)
50        } else {
51            Ok(Self { items })
52        }
53    }
54
55    /// Convert into a vector, preserving order.
56    #[must_use]
57    pub fn into_vec(self) -> Vec<T> {
58        self.items
59    }
60
61    /// Borrow as a slice.
62    #[must_use]
63    pub fn as_slice(&self) -> &[T] {
64        &self.items
65    }
66
67    /// Mutably borrow as a slice.
68    #[must_use]
69    pub fn as_mut_slice(&mut self) -> &mut [T] {
70        &mut self.items
71    }
72
73    /// Number of elements. Always at least 1.
74    #[must_use]
75    pub const fn len(&self) -> usize {
76        self.items.len()
77    }
78
79    /// Returns `false`; provided for API compatibility with sequence-like code.
80    #[must_use]
81    pub const fn is_empty(&self) -> bool {
82        false
83    }
84
85    /// First element in source order.
86    #[must_use]
87    pub fn first(&self) -> &T {
88        &self.items[0]
89    }
90
91    /// Last element in source order.
92    #[must_use]
93    pub fn last(&self) -> &T {
94        &self.items[self.items.len() - 1]
95    }
96
97    /// Split into the last element and the elements before it.
98    #[must_use]
99    pub fn split_last(&self) -> (&T, &[T]) {
100        let last_index = self.items.len() - 1;
101        (&self.items[last_index], &self.items[..last_index])
102    }
103
104    /// Iterate over all elements in source order.
105    pub fn iter(&self) -> std::slice::Iter<'_, T> {
106        self.items.iter()
107    }
108
109    /// Mutably iterate over all elements in source order.
110    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
111        self.items.iter_mut()
112    }
113
114    /// Append an item to the end of the sequence.
115    pub fn push(&mut self, item: T) {
116        self.items.push(item);
117    }
118
119    /// Map each item while preserving non-emptiness.
120    pub fn map<U>(self, f: impl FnMut(T) -> U) -> NonEmpty<U> {
121        NonEmpty {
122            items: self.items.into_iter().map(f).collect(),
123        }
124    }
125}
126
127impl<T> TryFrom<Vec<T>> for NonEmpty<T> {
128    type Error = EmptyVecError;
129
130    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
131        Self::try_from_vec(value)
132    }
133}
134
135impl<T> From<(T, Vec<T>)> for NonEmpty<T> {
136    fn from((first, rest): (T, Vec<T>)) -> Self {
137        Self::new(first, rest)
138    }
139}
140
141impl<T> From<T> for NonEmpty<T> {
142    fn from(first: T) -> Self {
143        Self::singleton(first)
144    }
145}
146
147impl<T> IntoIterator for NonEmpty<T> {
148    type Item = T;
149    type IntoIter = std::vec::IntoIter<T>;
150
151    fn into_iter(self) -> Self::IntoIter {
152        self.items.into_iter()
153    }
154}
155
156impl<'a, T> IntoIterator for &'a NonEmpty<T> {
157    type Item = &'a T;
158    type IntoIter = std::slice::Iter<'a, T>;
159
160    fn into_iter(self) -> Self::IntoIter {
161        self.items.iter()
162    }
163}
164
165impl<'a, T> IntoIterator for &'a mut NonEmpty<T> {
166    type Item = &'a mut T;
167    type IntoIter = std::slice::IterMut<'a, T>;
168
169    fn into_iter(self) -> Self::IntoIter {
170        self.items.iter_mut()
171    }
172}
173
174impl<T> Index<usize> for NonEmpty<T> {
175    type Output = T;
176
177    fn index(&self, index: usize) -> &Self::Output {
178        &self.items[index]
179    }
180}
181
182impl<T> IndexMut<usize> for NonEmpty<T> {
183    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
184        &mut self.items[index]
185    }
186}
187
188impl<T, const N: usize> TryFrom<[T; N]> for NonEmpty<T> {
189    type Error = EmptyVecError;
190
191    fn try_from(value: [T; N]) -> Result<Self, Self::Error> {
192        Self::try_from_vec(value.into_iter().collect())
193    }
194}