macroonz_compiler/bounded/
type_guard.rs1use super::{Bounded, Capped, Capping, Empty, NonEmpty, NonEmptyError, Overflow};
7
8impl<T, const N: usize> Bounded<T, N> {
9 #[must_use]
11 pub const fn empty() -> Self {
12 Self(Vec::new())
13 }
14
15 pub fn new(items: Vec<T>) -> Result<Self, Overflow> {
21 if items.len() <= N {
22 Ok(Self(items))
23 } else {
24 Err(Overflow {
25 capacity: N,
26 offered: items.len(),
27 })
28 }
29 }
30
31 #[must_use]
33 pub fn from_array<const M: usize>(items: [T; M]) -> Self {
34 const {
35 assert!(
36 M <= N,
37 "a fixed list longer than the ceiling it is declared under"
38 );
39 }
40 Self(Vec::from(items))
41 }
42
43 #[must_use]
45 pub fn as_slice(&self) -> &[T] {
46 self.0.as_slice()
47 }
48
49 pub fn iter(&self) -> impl Iterator<Item = &T> {
51 self.0.iter()
52 }
53
54 #[must_use]
56 pub fn len(&self) -> usize {
57 self.0.len()
58 }
59
60 #[must_use]
62 pub fn is_empty(&self) -> bool {
63 self.0.is_empty()
64 }
65
66 pub fn try_push(&mut self, item: T) -> Result<(), Overflow> {
72 let offered = self.0.len().saturating_add(1);
73 if offered > N {
74 return Err(Overflow {
75 capacity: N,
76 offered,
77 });
78 }
79 self.0.push(item);
80 Ok(())
81 }
82}
83
84impl<T, const N: usize> NonEmpty<T, N> {
85 #[must_use]
87 pub const fn one(value: T) -> Self {
88 const {
89 assert!(
90 N >= 1,
91 "a non-empty list under a ceiling that admits no item"
92 );
93 }
94 Self {
95 head: value,
96 tail: Vec::new(),
97 }
98 }
99
100 pub fn new(items: Vec<T>) -> Result<Self, NonEmptyError> {
106 let offered = items.len();
107 let mut rest = items.into_iter();
108 let Some(head) = rest.next() else {
109 return Err(NonEmptyError::Empty(Empty));
110 };
111 if offered <= N {
112 Ok(Self {
113 head,
114 tail: rest.collect(),
115 })
116 } else {
117 Err(NonEmptyError::Overflow(Overflow {
118 capacity: N,
119 offered,
120 }))
121 }
122 }
123
124 #[must_use]
126 pub const fn first(&self) -> &T {
127 &self.head
128 }
129
130 #[must_use]
132 pub fn split(&self) -> (&T, &[T]) {
133 (&self.head, self.tail.as_slice())
134 }
135
136 pub fn iter(&self) -> impl Iterator<Item = &T> {
138 self.into_iter()
139 }
140
141 #[must_use]
143 pub fn count(&self) -> usize {
144 self.tail.len().saturating_add(1)
145 }
146}
147
148impl<'held, T, const N: usize> IntoIterator for &'held NonEmpty<T, N> {
149 type Item = &'held T;
150 type IntoIter = core::iter::Chain<core::iter::Once<&'held T>, core::slice::Iter<'held, T>>;
151
152 fn into_iter(self) -> Self::IntoIter {
153 core::iter::once(&self.head).chain(self.tail.iter())
154 }
155}
156
157impl<T, const N: usize> Capped<T, N> {
158 #[must_use]
160 pub const fn all(items: NonEmpty<T, N>) -> Self {
161 Self {
162 items,
163 capping: Capping::Complete,
164 }
165 }
166
167 #[must_use]
169 pub fn first_n(first: T, rest: impl Iterator<Item = T>) -> Self {
170 const {
171 assert!(N >= 1, "a capped list under a ceiling that admits no item");
172 }
173 let mut tail = Vec::new();
174 let mut omitted = 0_usize;
175 for item in rest {
176 if tail.len() < N.saturating_sub(1) {
177 tail.push(item);
178 } else {
179 omitted = omitted.saturating_add(1);
180 }
181 }
182 Self {
183 items: NonEmpty { head: first, tail },
184 capping: capping_over(omitted),
185 }
186 }
187
188 #[must_use]
190 pub const fn items(&self) -> &NonEmpty<T, N> {
191 &self.items
192 }
193
194 #[must_use]
196 pub const fn capping(&self) -> Capping {
197 self.capping
198 }
199}
200
201const fn capping_over(omitted: usize) -> Capping {
203 if omitted == 0 {
204 Capping::Complete
205 } else {
206 Capping::Truncated { omitted }
207 }
208}