synkit_core/
punctuated.rs1#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum TrailingPolicy {
7 Optional,
9 Required,
11 Forbidden,
13}
14
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[derive(Debug, Clone)]
21pub struct PunctuatedInner<T, P> {
22 pub(crate) inner: Vec<(T, Option<P>)>,
23}
24
25impl<T, P> PunctuatedInner<T, P> {
26 #[inline]
27 pub fn new() -> Self {
28 Self { inner: Vec::new() }
29 }
30
31 #[inline]
32 pub fn with_capacity(capacity: usize) -> Self {
33 Self {
34 inner: Vec::with_capacity(capacity),
35 }
36 }
37
38 #[inline]
39 pub fn push_value(&mut self, value: T) {
40 self.inner.push((value, None));
41 }
42
43 #[inline]
44 pub fn push_punct(&mut self, punct: P) {
45 if let Some(last) = self.inner.last_mut() {
46 last.1 = Some(punct);
47 }
48 }
49
50 #[inline]
51 pub fn trailing_punct(&self) -> bool {
52 self.inner.last().is_some_and(|(_, p)| p.is_some())
53 }
54
55 #[inline]
56 pub fn len(&self) -> usize {
57 self.inner.len()
58 }
59
60 #[inline]
61 pub fn is_empty(&self) -> bool {
62 self.inner.is_empty()
63 }
64
65 #[inline]
66 pub fn capacity(&self) -> usize {
67 self.inner.capacity()
68 }
69
70 #[inline]
71 pub fn reserve(&mut self, additional: usize) {
72 self.inner.reserve(additional);
73 }
74
75 #[inline]
76 pub fn shrink_to_fit(&mut self) {
77 self.inner.shrink_to_fit();
78 }
79
80 #[inline]
81 pub fn clear(&mut self) {
82 self.inner.clear();
83 }
84
85 #[inline]
86 pub fn iter(&self) -> impl Iterator<Item = &T> {
87 self.inner.iter().map(|(v, _)| v)
88 }
89
90 #[inline]
91 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
92 self.inner.iter_mut().map(|(v, _)| v)
93 }
94
95 #[inline]
96 pub fn pairs(&self) -> impl Iterator<Item = (&T, Option<&P>)> {
97 self.inner.iter().map(|(v, p)| (v, p.as_ref()))
98 }
99
100 #[inline]
101 pub fn pairs_mut(&mut self) -> impl Iterator<Item = (&mut T, Option<&mut P>)> {
102 self.inner.iter_mut().map(|(v, p)| (v, p.as_mut()))
103 }
104
105 #[inline]
106 pub fn into_pairs(self) -> impl Iterator<Item = (T, Option<P>)> {
107 self.inner.into_iter()
108 }
109
110 #[inline]
111 pub fn first(&self) -> Option<&T> {
112 self.inner.first().map(|(v, _)| v)
113 }
114
115 #[inline]
116 pub fn last(&self) -> Option<&T> {
117 self.inner.last().map(|(v, _)| v)
118 }
119}
120
121impl<T, P> Default for PunctuatedInner<T, P> {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl<T, P> FromIterator<T> for PunctuatedInner<T, P> {
128 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
129 let inner: Vec<(T, Option<P>)> = iter.into_iter().map(|v| (v, None)).collect();
130 Self { inner }
131 }
132}
133
134macro_rules! impl_punctuated_wrapper {
141 (
142 $(#[$attr:meta])*
143 $name:ident,
144 $policy:expr,
145 $trailing_punct:expr
146 ) => {
147 $(#[$attr])*
148 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149 #[derive(Debug, Clone)]
150 pub struct $name<T, P>(PunctuatedInner<T, P>);
151
152 impl<T, P> $name<T, P> {
153 pub const POLICY: TrailingPolicy = $policy;
155
156 #[inline]
158 pub fn new() -> Self {
159 Self(PunctuatedInner::new())
160 }
161
162 #[inline]
164 pub fn with_capacity(capacity: usize) -> Self {
165 Self(PunctuatedInner::with_capacity(capacity))
166 }
167
168 #[inline]
170 pub fn push_value(&mut self, value: T) {
171 self.0.push_value(value);
172 }
173
174 #[inline]
176 pub fn push_punct(&mut self, punct: P) {
177 self.0.push_punct(punct);
178 }
179
180 #[inline]
187 pub fn trailing_punct(&self) -> bool {
188 $trailing_punct(&self.0)
189 }
190
191 #[inline]
193 pub fn into_inner(self) -> PunctuatedInner<T, P> {
194 self.0
195 }
196 }
197
198 impl<T, P> Default for $name<T, P> {
199 fn default() -> Self {
200 Self::new()
201 }
202 }
203
204 impl<T, P> IntoIterator for $name<T, P> {
205 type Item = T;
206 type IntoIter = std::iter::Map<std::vec::IntoIter<(T, Option<P>)>, fn((T, Option<P>)) -> T>;
207
208 fn into_iter(self) -> Self::IntoIter {
209 self.0.inner.into_iter().map(|(v, _)| v)
210 }
211 }
212
213 impl<T, P> FromIterator<T> for $name<T, P> {
214 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
215 Self(PunctuatedInner::from_iter(iter))
216 }
217 }
218
219 impl<T, P> std::ops::Deref for $name<T, P> {
220 type Target = PunctuatedInner<T, P>;
221
222 #[inline]
223 fn deref(&self) -> &Self::Target {
224 &self.0
225 }
226 }
227
228 impl<T, P> std::ops::DerefMut for $name<T, P> {
229 #[inline]
230 fn deref_mut(&mut self) -> &mut Self::Target {
231 &mut self.0
232 }
233 }
234
235 impl<T, P> AsRef<PunctuatedInner<T, P>> for $name<T, P> {
236 #[inline]
237 fn as_ref(&self) -> &PunctuatedInner<T, P> {
238 &self.0
239 }
240 }
241
242 impl<T, P> AsMut<PunctuatedInner<T, P>> for $name<T, P> {
243 #[inline]
244 fn as_mut(&mut self) -> &mut PunctuatedInner<T, P> {
245 &mut self.0
246 }
247 }
248 };
249}
250
251impl_punctuated_wrapper!(
252 Punctuated,
275 TrailingPolicy::Optional,
276 |inner: &PunctuatedInner<T, P>| inner.trailing_punct()
277);
278
279impl_punctuated_wrapper!(
280 Terminated,
290 TrailingPolicy::Required,
291 |_: &PunctuatedInner<T, P>| true
292);
293
294impl_punctuated_wrapper!(
295 Separated,
305 TrailingPolicy::Forbidden,
306 |_: &PunctuatedInner<T, P>| false
307);