Skip to main content

zrx_id/id/
sequence.rs

1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// All contributions are certified under the DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Sequence.
27
28use std::iter::once;
29use std::slice::Iter;
30use std::vec::IntoIter;
31
32use zrx_scheduler::Value;
33
34mod element;
35pub mod filter;
36
37pub use element::Element;
38pub use filter::Filter;
39
40// ----------------------------------------------------------------------------
41// Structs
42// ----------------------------------------------------------------------------
43
44/// Sequence.
45///
46/// Sequences are ordered collections of expressions that can be used to match
47/// identifiers. Sequences can contain gaps, which allow to implement flexible
48/// matching of identifiers with varying numbers of elements, including but
49/// not limited to prefix and suffix matching.
50///
51/// Each [`Element`] of a [`Sequence`] can either be an [`Expression`][] or a
52/// [`Gap`][]. An [`Expression`][] is a logical combination of one or multiple
53/// [`Id`][] and [`Selector`][] instances, while a [`Gap`][] represents a
54/// wildcard that can match any number of elements, including zero.
55///
56/// The following convenience constructors are provided:
57///
58/// - [`Sequence::prefix`]: Creates a sequence for prefix matching.
59/// - [`Sequence::suffix`]: Creates a sequence for suffix matching.
60///
61/// [`Expression`]: crate::id::expression::Expression
62/// [`Gap`]: crate::id::sequence::Element::Gap
63/// [`Id`]: crate::id::Id
64/// [`Selector`]: crate::id::selector::Selector
65///
66/// # Examples
67///
68/// ```
69/// # use std::error::Error;
70/// # fn main() -> Result<(), Box<dyn Error>> {
71/// use zrx_id::{selector, Sequence};
72///
73/// // Create sequence
74/// let sequence = Sequence::from([
75///     selector!(location = "zensical.toml")?,
76///     selector!(location = "**/*.md")?,
77/// ]);
78/// # Ok(())
79/// # }
80/// ```
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct Sequence {
83    /// Sequence elements.
84    elements: Box<[Element]>,
85}
86
87// ----------------------------------------------------------------------------
88// Implementations
89// ----------------------------------------------------------------------------
90
91impl Sequence {
92    /// Creates a sequence where the given elements are a prefix.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// # use std::error::Error;
98    /// # fn main() -> Result<(), Box<dyn Error>> {
99    /// use zrx_id::{selector, Sequence};
100    ///
101    /// // Create sequence for a prefix
102    /// let sequence = Sequence::prefix([
103    ///     selector!(location = "zensical.toml")?,
104    /// ]);
105    /// # Ok(())
106    /// # }
107    /// ```
108    #[inline]
109    #[must_use]
110    pub fn prefix<T>(sequence: T) -> Self
111    where
112        T: Into<Self>,
113    {
114        let sequence = sequence.into();
115        let elements = sequence.into_iter().chain(once(Element::Gap));
116        Self {
117            elements: elements.collect::<Vec<_>>().into_boxed_slice(),
118        }
119    }
120
121    /// Creates a sequence where the given elements are a suffix.
122    ///
123    /// # Examples
124    ///
125    /// ```
126    /// # use std::error::Error;
127    /// # fn main() -> Result<(), Box<dyn Error>> {
128    /// use zrx_id::{selector, Sequence};
129    ///
130    /// // Create sequence for a suffix
131    /// let sequence = Sequence::suffix([
132    ///     selector!(location = "**/*.md")?,
133    /// ]);
134    /// # Ok(())
135    /// # }
136    /// ```
137    #[inline]
138    #[must_use]
139    pub fn suffix<T>(sequence: T) -> Self
140    where
141        T: Into<Self>,
142    {
143        let sequence = sequence.into();
144        let elements = once(Element::Gap).chain(sequence);
145        Self {
146            elements: elements.collect::<Vec<_>>().into_boxed_slice(),
147        }
148    }
149
150    /// Creates an iterator over the sequence.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// # use std::error::Error;
156    /// # fn main() -> Result<(), Box<dyn Error>> {
157    /// use zrx_id::{selector, Sequence};
158    ///
159    /// // Create sequence
160    /// let sequence = Sequence::from([
161    ///     selector!(location = "zensical.toml")?,
162    ///     selector!(location = "**/*.md")?,
163    /// ]);
164    ///
165    /// // Create iterator over sequence
166    /// for element in sequence.iter() {
167    ///     println!("{element:?}");
168    /// }
169    /// # Ok(())
170    /// # }
171    /// ```
172    #[inline]
173    pub fn iter(&self) -> Iter<'_, Element> {
174        self.elements.iter()
175    }
176}
177
178#[allow(clippy::must_use_candidate)]
179impl Sequence {
180    /// Returns the number of elements.
181    #[inline]
182    pub fn len(&self) -> usize {
183        self.elements.len()
184    }
185
186    /// Returns whether there are any elements.
187    #[inline]
188    pub fn is_empty(&self) -> bool {
189        self.elements.is_empty()
190    }
191}
192
193// ----------------------------------------------------------------------------
194// Trait implementations
195// ----------------------------------------------------------------------------
196
197impl Value for Sequence {}
198
199// ----------------------------------------------------------------------------
200
201impl<E> From<E> for Sequence
202where
203    E: Into<Element>,
204{
205    /// Creates a sequence from an element.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # use std::error::Error;
211    /// # fn main() -> Result<(), Box<dyn Error>> {
212    /// use zrx_id::{selector, Sequence};
213    ///
214    /// // Create sequence
215    /// let sequence = Sequence::from(
216    ///     selector!(location = "zensical.toml")?,
217    /// );
218    /// # Ok(())
219    /// # }
220    /// ```
221    #[inline]
222    fn from(value: E) -> Self {
223        Self::from_iter([value])
224    }
225}
226
227impl<E, const N: usize> From<[E; N]> for Sequence
228where
229    E: Into<Element>,
230{
231    /// Creates a sequence from a slice of elements.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// # use std::error::Error;
237    /// # fn main() -> Result<(), Box<dyn Error>> {
238    /// use zrx_id::{selector, Sequence};
239    ///
240    /// // Create sequence
241    /// let sequence = Sequence::from([
242    ///     selector!(location = "zensical.toml")?,
243    ///     selector!(location = "**/*.md")?,
244    /// ]);
245    /// # Ok(())
246    /// # }
247    /// ```
248    #[inline]
249    fn from(value: [E; N]) -> Self {
250        Self::from_iter(value)
251    }
252}
253
254impl<E> From<&[E]> for Sequence
255where
256    E: Into<Element> + Clone,
257{
258    /// Creates a sequence from a slice of elements.
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// # use std::error::Error;
264    /// # fn main() -> Result<(), Box<dyn Error>> {
265    /// use zrx_id::{selector, Sequence};
266    ///
267    /// // Create sequence
268    /// let sequence = Sequence::from(&[
269    ///     selector!(location = "zensical.toml")?,
270    ///     selector!(location = "**/*.md")?,
271    /// ][..]);
272    /// # Ok(())
273    /// # }
274    /// ```
275    #[inline]
276    fn from(value: &[E]) -> Self {
277        value.iter().cloned().collect()
278    }
279}
280
281impl<E> From<Vec<E>> for Sequence
282where
283    E: Into<Element>,
284{
285    /// Creates a sequence from a vector of elements.
286    ///
287    /// # Examples
288    ///
289    /// ```
290    /// # use std::error::Error;
291    /// # fn main() -> Result<(), Box<dyn Error>> {
292    /// use zrx_id::{selector, Sequence};
293    ///
294    /// // Create sequence
295    /// let sequence = Sequence::from(vec![
296    ///     selector!(location = "zensical.toml")?,
297    ///     selector!(location = "**/*.md")?,
298    /// ]);
299    /// # Ok(())
300    /// # }
301    /// ```
302    #[inline]
303    fn from(value: Vec<E>) -> Self {
304        Self::from_iter(value)
305    }
306}
307
308// ----------------------------------------------------------------------------
309
310impl<E> FromIterator<E> for Sequence
311where
312    E: Into<Element>,
313{
314    /// Creates a sequence from an iterator.
315    ///
316    /// # Examples
317    ///
318    /// ```
319    /// # use std::error::Error;
320    /// # fn main() -> Result<(), Box<dyn Error>> {
321    /// use zrx_id::{selector, Sequence};
322    ///
323    /// // Create sequence from iterator
324    /// let sequence = Sequence::from_iter([
325    ///     selector!(location = "zensical.toml")?,
326    ///     selector!(location = "**/*.md")?,
327    /// ]);
328    /// # Ok(())
329    /// # }
330    /// ```
331    #[inline]
332    fn from_iter<T>(iter: T) -> Self
333    where
334        T: IntoIterator<Item = E>,
335    {
336        let elements = iter.into_iter().map(Into::into);
337        Self {
338            elements: elements.collect::<Vec<_>>().into_boxed_slice(),
339        }
340    }
341}
342
343impl<'a> IntoIterator for &'a Sequence {
344    type Item = &'a Element;
345    type IntoIter = Iter<'a, Element>;
346
347    /// Creates an iterator over the sequence.
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// # use std::error::Error;
353    /// # fn main() -> Result<(), Box<dyn Error>> {
354    /// use zrx_id::{selector, Sequence};
355    ///
356    /// // Create sequence
357    /// let sequence = Sequence::from([
358    ///     selector!(location = "zensical.toml")?,
359    ///     selector!(location = "**/*.md")?,
360    /// ]);
361    ///
362    /// // Create iterator over sequence
363    /// for element in &sequence {
364    ///     println!("{element:?}");
365    /// }
366    /// # Ok(())
367    /// # }
368    /// ```
369    #[inline]
370    fn into_iter(self) -> Self::IntoIter {
371        self.iter()
372    }
373}
374
375impl IntoIterator for Sequence {
376    type Item = Element;
377    type IntoIter = IntoIter<Self::Item>;
378
379    /// Creates a consuming iterator over the sequence.
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// # use std::error::Error;
385    /// # fn main() -> Result<(), Box<dyn Error>> {
386    /// use zrx_id::{selector, Sequence};
387    ///
388    /// // Create sequence
389    /// let sequence = Sequence::from([
390    ///     selector!(location = "zensical.toml")?,
391    ///     selector!(location = "**/*.md")?,
392    /// ]);
393    ///
394    /// // Create iterator over sequence
395    /// for element in sequence {
396    ///     println!("{element:?}");
397    /// }
398    /// # Ok(())
399    /// # }
400    /// ```
401    #[inline]
402    fn into_iter(self) -> Self::IntoIter {
403        self.elements.into_iter()
404    }
405}
406
407// ----------------------------------------------------------------------------
408
409impl Default for Sequence {
410    /// Creates a sequence that matches everything.
411    ///
412    /// # Examples
413    ///
414    /// ```
415    /// use zrx_id::Sequence;
416    ///
417    /// // Create empty sequence
418    /// let sequence = Sequence::default();
419    /// assert!(!sequence.is_empty());
420    /// ```
421    #[inline]
422    fn default() -> Self {
423        Self::from(Element::Gap)
424    }
425}