1use crate::Rational;
4use std::fmt;
5
6#[macro_export]
8macro_rules! span {
9 ($n1:literal/$d1:literal, $n2:literal/$d2:literal) => {{
10 span!($n1 / $d1, $crate::Rational::new_raw($n2, $d2))
11 }};
12 ($n1:literal/$d1:literal, $r2:expr) => {{
13 span!($crate::Rational::new_raw($n1, $d1), $r2)
14 }};
15 ($r1:expr, $n2:literal/$d2:literal) => {{
16 span!($r1, $crate::Rational::new_raw($n2, $d2))
17 }};
18 ($r1:expr, $r2:expr) => {{
19 $crate::Span::new($r1, $r2)
20 }};
21 ($n:literal / $d:literal) => {{
22 span!($crate::Rational::new_raw($n, $d))
23 }};
24 ($r:expr) => {{
25 $crate::Span::instant($r)
26 }};
27}
28
29#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
31pub struct Span {
32 pub start: Rational,
33 pub end: Rational,
34}
35
36impl Span {
37 pub fn new(start: Rational, end: Rational) -> Self {
38 Span { start, end }
39 }
40
41 pub fn instant(start @ end: Rational) -> Self {
42 Span { start, end }
43 }
44
45 pub fn len(&self) -> Rational {
46 self.end - self.start
47 }
48
49 pub fn cycles(self) -> impl Iterator<Item = Self> {
50 let Span { mut start, end } = self;
51 std::iter::from_fn(move || {
52 if start >= end {
53 None
54 } else if start >= end.floor() {
55 let span = Span { start, end };
56 start = end;
57 Some(span)
58 } else {
59 let this_end = start.floor() + 1;
60 let span = Span {
61 start,
62 end: this_end,
63 };
64 start = this_end;
65 Some(span)
66 }
67 })
68 }
69
70 pub fn map(self, f: impl Fn(Rational) -> Rational) -> Self {
71 span!(f(self.start), f(self.end))
72 }
73
74 pub fn map_len(self, f: impl Fn(Rational) -> Rational) -> Self {
75 let new_len = f(self.len());
76 let new_end = self.start + new_len;
77 span!(self.start, new_end)
78 }
79
80 pub fn contains(&self, point: Rational) -> bool {
82 self.start <= point && point < self.end
83 }
84
85 pub fn intersect(self, other: Self) -> Option<Self> {
89 let start = std::cmp::max(self.start, other.start);
90 let end = std::cmp::min(self.end, other.end);
91 if end <= start {
92 None
93 } else {
94 Some(Span { start, end })
95 }
96 }
97
98 pub fn difference(self, other: Self) -> (Option<Self>, Option<Self>) {
104 let pre = if self.start <= other.start {
105 None
106 } else {
107 Some(Span::new(other.start, std::cmp::min(self.start, other.end)))
108 };
109 let post = if other.end <= self.end {
110 None
111 } else {
112 Some(Span::new(std::cmp::max(self.end, other.start), other.end))
113 };
114 (pre, post)
115 }
116}
117
118impl fmt::Debug for Span {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 write!(f, "Span({}, {})", self.start, self.end)
121 }
122}
123
124impl fmt::Display for Span {
125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126 write!(f, "({}, {})", self.start, self.end)
127 }
128}
129
130#[test]
131fn test_span_macro() {
132 assert_eq!(
133 span!(0 / 1, 1 / 1),
134 Span::new(Rational::new(0, 1), Rational::new(1, 1))
135 );
136 assert_eq!(
137 span!(Rational::new(1, 1), 4 / 1),
138 span!(1 / 1, Rational::new(4, 1)),
139 );
140}
141
142#[test]
143fn test_span_fmt() {
144 for n in 0..10 {
145 let a = Rational::new(n, 10);
146 let b = Rational::new(n + 1, 10);
147 let span = span!(a, b);
148 println!("{:?} | {}", span, span);
149 }
150}
151
152#[test]
153fn test_span_intersect() {
154 assert_eq!(
155 span!(0 / 1, 3 / 4).intersect(span!(1 / 4, 1 / 1)),
156 Some(span!(1 / 4, 3 / 4))
157 );
158 assert_eq!(span!(0 / 1, 1 / 4).intersect(span!(3 / 4, 1 / 1)), None);
159}
160
161#[test]
162fn test_span_difference() {
163 let s1 = Span::new(Rational::new(2, 1), Rational::new(5, 1));
164
165 let other = Span::new(Rational::new(0, 1), Rational::new(1, 1));
167 assert_eq!(s1.difference(other), (Some(other), None));
168
169 let other = Span::new(Rational::new(6, 1), Rational::new(8, 1));
171 assert_eq!(s1.difference(other), (None, Some(other)));
172
173 let other = Span::new(Rational::new(1, 1), Rational::new(3, 1));
175 assert_eq!(
176 s1.difference(other),
177 (
178 Some(Span::new(Rational::new(1, 1), Rational::new(2, 1))),
179 None
180 )
181 );
182
183 let other = Span::new(Rational::new(4, 1), Rational::new(6, 1));
185 assert_eq!(
186 s1.difference(other),
187 (
188 None,
189 Some(Span::new(Rational::new(5, 1), Rational::new(6, 1)))
190 )
191 );
192
193 let other = Span::new(Rational::new(3, 1), Rational::new(4, 1));
195 assert_eq!(s1.difference(other), (None, None));
196
197 let other = Span::new(Rational::new(1, 1), Rational::new(6, 1));
199 assert_eq!(
200 s1.difference(other),
201 (
202 Some(Span::new(Rational::new(1, 1), Rational::new(2, 1))),
203 Some(Span::new(Rational::new(5, 1), Rational::new(6, 1)))
204 )
205 );
206}