1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::position::Position;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
8pub struct Range {
9 pub start: Position,
10 pub end: Position,
11}
12
13impl Range {
14 pub const EMPTY: Self = Self {
15 start: Position::ZERO,
16 end: Position::ZERO,
17 };
18
19 #[must_use]
20 pub const fn new(start: Position, end: Position) -> Self {
21 Self { start, end }
22 }
23
24 #[must_use]
25 pub fn point(p: Position) -> Self {
26 Self { start: p, end: p }
27 }
28
29 #[must_use]
30 pub fn is_empty(self) -> bool {
31 self.start == self.end
32 }
33
34 #[must_use]
35 pub fn contains(self, p: Position) -> bool {
36 p >= self.start && p < self.end
37 }
38
39 #[must_use]
42 pub fn normalized(self) -> Self {
43 if self.start <= self.end {
44 self
45 } else {
46 Self {
47 start: self.end,
48 end: self.start,
49 }
50 }
51 }
52
53 #[must_use]
55 pub fn union(self, other: Self) -> Self {
56 let a = self.normalized();
57 let b = other.normalized();
58 Self {
59 start: a.start.min(b.start),
60 end: a.end.max(b.end),
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn contains_half_open() {
71 let r = Range::new(Position::new(0, 0), Position::new(0, 5));
72 assert!(r.contains(Position::new(0, 0)));
73 assert!(r.contains(Position::new(0, 4)));
74 assert!(!r.contains(Position::new(0, 5))); }
76
77 #[test]
78 fn normalize_swaps_inverted() {
79 let r = Range::new(Position::new(1, 4), Position::new(0, 2));
80 let n = r.normalized();
81 assert_eq!(n.start, Position::new(0, 2));
82 assert_eq!(n.end, Position::new(1, 4));
83 }
84
85 #[test]
86 fn union_covers_both() {
87 let a = Range::new(Position::new(0, 0), Position::new(0, 4));
88 let b = Range::new(Position::new(1, 0), Position::new(1, 5));
89 let u = a.union(b);
90 assert_eq!(u.start, Position::new(0, 0));
91 assert_eq!(u.end, Position::new(1, 5));
92 }
93}