lset/line.rs
1// SPDX-License-Identifier: Apache-2.0
2
3use super::*;
4use core::{cmp::Ordering, ops::*};
5
6/// Expresses a linear set by its starting and termination points
7///
8/// This type is fully isomorphic with `core::ops::Range` and `Span`. However,
9/// unlike `core::ops::Range`, this type is not an iterator and therefore can
10/// implement `Copy`. Points may have any number of dimensions.
11#[repr(C)]
12#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
13pub struct Line<T> {
14 /// The start point
15 pub start: T,
16
17 /// The first point excluded by the set
18 pub end: T,
19}
20
21impl<T> Line<T> {
22 /// Create a new line
23 ///
24 /// # Example
25 ///
26 /// ```
27 /// let line = lset::Line::new(5, 10);
28 /// assert_eq!(line.start, 5);
29 /// assert_eq!(line.end, 10);
30 /// ```
31 #[inline(always)]
32 pub const fn new(start: T, end: T) -> Self {
33 Self { start, end }
34 }
35
36 /// Indicates whether the line is empty
37 ///
38 /// # Example
39 ///
40 /// ```
41 /// use lset::*;
42 /// assert!(Line::from(2..2).is_empty());
43 /// assert!(!Line::from(2..3).is_empty());
44 /// ```
45 #[inline(always)]
46 pub fn is_empty(&self) -> bool
47 where
48 T: PartialEq,
49 {
50 self.start == self.end
51 }
52}
53
54impl<T: PartialOrd> Line<T> {
55 /// Returns the intersection between the sets, if any.
56 ///
57 /// ```
58 /// use lset::*;
59 ///
60 /// let a = Line::new(0, 5);
61 /// let b = Line::new(2, 7);
62 /// let c = Line::new(5, 10);
63 ///
64 /// assert_eq!(a.intersection(b), Some(Line::new(2, 5)));
65 /// assert_eq!(b.intersection(c), Some(Line::new(5, 7)));
66 /// assert_eq!(a.intersection(a), Some(a));
67 /// assert_eq!(b.intersection(b), Some(b));
68 /// assert_eq!(c.intersection(c), Some(c));
69 /// assert_eq!(a.intersection(c), None);
70 /// ```
71 pub fn intersection(self, other: Self) -> Option<Self> {
72 let start = if other.start >= self.start && other.start < self.end {
73 Some(other.start)
74 } else {
75 None
76 };
77
78 let end = if other.end > self.start && other.end <= self.end {
79 Some(other.end)
80 } else {
81 None
82 };
83
84 match (start, end) {
85 (Some(start), Some(end)) => Some(Line::new(start, end)),
86 (Some(start), None) => Some(Line::new(start, self.end)),
87 (None, Some(end)) => Some(Line::new(self.start, end)),
88 (None, None) => None,
89 }
90 }
91}
92
93impl<T: Add<T, Output = T>> Add<T> for Line<T> {
94 type Output = Self;
95
96 /// Grows the line by the size of the operand
97 ///
98 /// # Example
99 ///
100 /// ```
101 /// let before = lset::Line::new(5, 10);
102 /// let after = before + 5;
103 /// assert_eq!(after.start, 5);
104 /// assert_eq!(after.end, 15);
105 /// ```
106 #[inline(always)]
107 fn add(self, rhs: T) -> Self::Output {
108 Self {
109 start: self.start,
110 end: self.end + rhs,
111 }
112 }
113}
114
115impl<T: AddAssign<T>> AddAssign<T> for Line<T> {
116 /// Grows the line by the size of the operand
117 ///
118 /// # Example
119 ///
120 /// ```
121 /// let mut line = lset::Line::new(5, 10);
122 /// line += 5;
123 /// assert_eq!(line.start, 5);
124 /// assert_eq!(line.end, 15);
125 /// ```
126 #[inline(always)]
127 fn add_assign(&mut self, rhs: T) {
128 self.end += rhs;
129 }
130}
131
132impl<T: Sub<T, Output = T>> Sub<T> for Line<T> {
133 type Output = Self;
134
135 /// Shrinks the line by the size of the operand
136 ///
137 /// # Example
138 ///
139 /// ```
140 /// let before = lset::Line::new(5, 10);
141 /// let after = before - 5;
142 /// assert_eq!(after.start, 5);
143 /// assert_eq!(after.end, 5);
144 /// ```
145 #[inline(always)]
146 fn sub(self, rhs: T) -> Self::Output {
147 Self {
148 start: self.start,
149 end: self.end - rhs,
150 }
151 }
152}
153
154impl<T: SubAssign<T>> SubAssign<T> for Line<T> {
155 /// Shrinks the line by the size of the operand
156 ///
157 /// # Example
158 ///
159 /// ```
160 /// let mut line = lset::Line::new(5, 10);
161 /// line -= 5;
162 /// assert_eq!(line.start, 5);
163 /// assert_eq!(line.end, 5);
164 /// ```
165 #[inline(always)]
166 fn sub_assign(&mut self, rhs: T) {
167 self.end -= rhs;
168 }
169}
170
171impl<T: Copy + Sub<T, Output = T>> Shl<T> for Line<T> {
172 type Output = Self;
173
174 /// Shifts the line downwards without changing size
175 ///
176 /// # Example
177 ///
178 /// ```
179 /// let before = lset::Line::new(5, 10);
180 /// let after = before << 5;
181 /// assert_eq!(after.start, 0);
182 /// assert_eq!(after.end, 5);
183 /// ```
184 #[inline(always)]
185 fn shl(self, rhs: T) -> Self::Output {
186 Self {
187 start: self.start - rhs,
188 end: self.end - rhs,
189 }
190 }
191}
192
193impl<T: Copy + SubAssign<T>> ShlAssign<T> for Line<T> {
194 /// Shifts the line downwards without changing size
195 ///
196 /// # Example
197 ///
198 /// ```
199 /// let mut line = lset::Line::new(5, 10);
200 /// line <<= 5;
201 /// assert_eq!(line.start, 0);
202 /// assert_eq!(line.end, 5);
203 /// ```
204 #[inline(always)]
205 fn shl_assign(&mut self, rhs: T) {
206 self.start -= rhs;
207 self.end -= rhs;
208 }
209}
210
211impl<T: Copy + Add<T, Output = T>> Shr<T> for Line<T> {
212 type Output = Self;
213
214 /// Shifts the line upwards without changing size
215 ///
216 /// # Example
217 ///
218 /// ```
219 /// let before = lset::Line::new(5, 10);
220 /// let after = before >> 5;
221 /// assert_eq!(after.start, 10);
222 /// assert_eq!(after.end, 15);
223 /// ```
224 #[inline(always)]
225 fn shr(self, rhs: T) -> Self::Output {
226 Self {
227 start: self.start + rhs,
228 end: self.end + rhs,
229 }
230 }
231}
232
233impl<T: Copy + AddAssign<T>> ShrAssign<T> for Line<T> {
234 /// Shifts the line upwards without changing size
235 ///
236 /// # Example
237 ///
238 /// ```
239 /// let mut line = lset::Line::new(5, 10);
240 /// line >>= 5;
241 /// assert_eq!(line.start, 10);
242 /// assert_eq!(line.end, 15);
243 /// ```
244 #[inline(always)]
245 fn shr_assign(&mut self, rhs: T) {
246 self.start += rhs;
247 self.end += rhs;
248 }
249}
250
251impl<T: PartialOrd> PartialOrd for Line<T> {
252 /// Compares two `Line` types.
253 ///
254 /// # Example
255 ///
256 /// ```
257 /// use lset::*;
258 /// assert!(Line::new(5, 10) <= Line::new(5, 10));
259 /// assert!(Line::new(5, 10) >= Line::new(5, 10));
260 /// assert!(Line::new(5, 10) < Line::new(10, 15));
261 /// assert!(Line::new(10, 15) > Line::new(5, 10));
262 /// ```
263 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
264 if self == other {
265 Some(Ordering::Equal)
266 } else if self.start >= other.end {
267 Some(Ordering::Greater)
268 } else if self.end <= other.start {
269 Some(Ordering::Less)
270 } else {
271 None
272 }
273 }
274}
275
276impl<T> From<Range<T>> for Line<T> {
277 /// Converts a `Range` into a `Line`
278 ///
279 /// # Example
280 ///
281 /// ```
282 /// use lset::*;
283 /// assert_eq!(Line::new(5, 10), Line::from(5..10));
284 /// assert_eq!(Line::new(5, 10), (5..10).into());
285 /// ```
286 #[inline(always)]
287 fn from(value: Range<T>) -> Self {
288 Self {
289 start: value.start,
290 end: value.end,
291 }
292 }
293}
294
295impl<T> From<Line<T>> for Range<T> {
296 /// Converts a `Line` into a `Range`
297 ///
298 /// # Example
299 ///
300 /// ```
301 /// use lset::*;
302 /// assert_eq!(5..10, std::ops::Range::from(Line::new(5, 10)));
303 /// assert_eq!(5..10, Line::new(5, 10).into());
304 /// ```
305 #[inline(always)]
306 fn from(value: Line<T>) -> Self {
307 Self {
308 start: value.start,
309 end: value.end,
310 }
311 }
312}
313
314impl<T: Clone + Add<U, Output = T>, U> From<Span<T, U>> for Line<T> {
315 /// Converts a `Span` into a `Line`
316 ///
317 /// # Example
318 ///
319 /// ```
320 /// use lset::*;
321 /// assert_eq!(Line::new(5, 10), Line::from(Span::new(5, 5)));
322 /// assert_eq!(Line::new(5, 10), Span::new(5, 5).into());
323 /// ```
324 #[inline(always)]
325 fn from(value: Span<T, U>) -> Self {
326 Self {
327 start: value.start.clone(),
328 end: value.start + value.count,
329 }
330 }
331}
332
333impl<T: PartialOrd> Contains<T> for Line<T> {
334 /// Indicates whether the line contains a point
335 ///
336 /// # Example
337 ///
338 /// ```
339 /// use lset::*;
340 /// assert!(!Line::from(2..3).contains(&1));
341 /// assert!(Line::from(2..3).contains(&2));
342 /// assert!(!Line::from(2..3).contains(&3));
343
344 /// assert!(!Line::from(3..2).contains(&1));
345 /// assert!(!Line::from(3..2).contains(&2));
346 /// assert!(!Line::from(3..2).contains(&3));
347 /// ```
348 #[inline(always)]
349 fn contains(&self, value: &T) -> bool {
350 if self.start <= self.end {
351 &self.start <= value && value < &self.end
352 } else {
353 false
354 }
355 }
356}
357
358impl<T: PartialOrd> Contains<Self> for Line<T> {
359 /// Indicates whether the line contains another line
360 ///
361 /// # Example
362 ///
363 /// ```
364 /// use lset::*;
365 /// assert!(Line::from(4..8).contains(&Line::from(5..7)));
366 /// assert!(Line::from(4..8).contains(&Line::from(4..7)));
367 /// assert!(Line::from(4..8).contains(&Line::from(5..8)));
368 /// assert!(Line::from(4..8).contains(&Line::from(4..8)));
369 /// assert!(!Line::from(4..8).contains(&Line::from(3..8)));
370 /// assert!(!Line::from(4..8).contains(&Line::from(4..9)));
371 /// assert!(!Line::from(4..8).contains(&Line::from(3..9)));
372 /// assert!(!Line::from(4..8).contains(&Line::from(2..10)));
373 /// assert!(!Line::from(4..8).contains(&Line::from(6..5)));
374 /// assert!(!Line::from(7..3).contains(&Line::from(5..6)));
375 /// ```
376 #[inline(always)]
377 fn contains(&self, value: &Self) -> bool {
378 if self.start <= self.end && value.start <= value.end {
379 self.start <= value.start && value.end <= self.end
380 } else {
381 false
382 }
383 }
384}
385
386impl<T: PartialOrd> Split<Self> for Line<T> {
387 /// Splits a line by another line
388 ///
389 /// # Example
390 ///
391 /// ```
392 /// use lset::*;
393 /// let line = Line::from(2..5);
394 /// assert_eq!(line.split(Line::from(1..4)), None);
395 /// assert_eq!(line.split(Line::from(3..6)), None);
396 /// assert_eq!(line.split(Line::from(2..2)), None);
397 /// assert_eq!(line.split(Line::from(2..3)), Some((Line::from(2..2), Line::from(3..5))));
398 /// assert_eq!(line.split(Line::from(3..3)), None);
399 /// assert_eq!(line.split(Line::from(3..4)), Some((Line::from(2..3), Line::from(4..5))));
400 /// assert_eq!(line.split(Line::from(4..4)), None);
401 /// assert_eq!(line.split(Line::from(4..5)), Some((Line::from(2..4), Line::from(5..5))));
402 /// assert_eq!(line.split(Line::from(5..5)), None);
403 /// assert_eq!(line.split(line), Some((Line::from(2..2), Line::from(5..5))));
404 /// ```
405 #[inline(always)]
406 fn split(self, at: Self) -> Option<(Self, Self)> {
407 if at.start == at.end {
408 return None;
409 }
410
411 if !self.contains(&at) {
412 return None;
413 }
414
415 let l = Self {
416 start: self.start,
417 end: at.start,
418 };
419
420 let r = Self {
421 start: at.end,
422 end: self.end,
423 };
424
425 Some((l, r))
426 }
427}
428
429impl<T: PartialOrd + Copy> Split<T> for Line<T> {
430 /// Splits a line at a point
431 ///
432 /// # Example
433 ///
434 /// ```
435 /// use lset::*;
436 /// let line = Line::from(2..4);
437 /// assert_eq!(line.split(1), None);
438 /// assert_eq!(line.split(2), Some((Line::from(2..2), line)));
439 /// assert_eq!(line.split(3), Some((Line::from(2..3), Line::from(3..4))));
440 /// assert_eq!(line.split(4), Some((line, Line::from(4..4))));
441 /// assert_eq!(line.split(5), None);
442 /// ```
443 #[inline(always)]
444 fn split(self, at: T) -> Option<(Self, Self)> {
445 if at < self.start || at > self.end {
446 return None;
447 }
448
449 let l = Self {
450 start: self.start,
451 end: at,
452 };
453
454 let r = Self {
455 start: at,
456 end: self.end,
457 };
458
459 Some((l, r))
460 }
461}