1use core::num::NonZeroUsize;
2
3use crate::{pattern::{Pattern, Never}, prelude::Sep};
4
5
6#[macro_export]
26macro_rules! interval {
27 ($n: expr) => {
28 ::string_iter::patterns::Interval::new(0, [$n])
29 };
30 ($a: expr, $($b: expr),*) => {
31 ::string_iter::patterns::Interval::new(0, [$a, $($b),*])
32 };
33 ($n: expr => $adv: expr) => {
34 ::string_iter::patterns::Interval::new($adv, [$n])
35 };
36 ($a: expr, $($b: expr),* => $adv: expr) => {
37 ::string_iter::patterns::Interval::new($adv, [$a, $($b),*])
38 };
39}
40
41pub struct Interval<const N: usize> {
45 cursor: isize,
46 interval: [NonZeroUsize; N],
47}
48
49impl<const N: usize> Interval<N> {
50 #[doc(hidden)]
51 pub const fn new(mut cursor: isize, lengths: [usize; N]) -> Self {
52 assert!(N != 0);
53 let mut count = 0;
54 let mut sum = 0;
55 let mut interval = [NonZeroUsize::MIN; N];
56 while count < N {
57 assert!(lengths[count] > 0, "expected non-zero length");
58 sum += lengths[count];
59 interval[count] = match NonZeroUsize::new(sum){
60 Some(v) => v,
61 None => panic!("expected non-zero length")
62 };
63 count += 1;
64 }
65 if cursor.is_positive() {
66 cursor = cursor % interval[N-1].get() as isize;
67 }
68 Self {
69 cursor,
70 interval,
71 }
72 }
73
74 #[doc(hidden)]
75 const fn len(&self) -> isize{
76 self.interval[N-1].get() as isize
77 }
78}
79
80impl<const N: usize> Pattern for Interval<N> {
81 type Err = Never;
82
83 fn sep(&self) -> Sep {
84 Sep::Yield
86 }
87
88 fn matches(&mut self, _: char, _: &str) -> Result<bool, Self::Err> {
89 self.cursor += 1;
90 if self.cursor.is_negative() {
91 return Ok(false);
92 }
93 self.cursor = self.cursor % self.len();
94 Ok(self.cursor == 0 ||
95 self.interval.iter().any(|x| x.get() == self.cursor as usize))
96 }
97}