1use std::ops::Range;
2
3use serde::{Deserialize, Serialize};
4
5use crate::CharStringExt;
6
7#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
11pub struct Span {
12 pub start: usize,
13 pub end: usize,
14}
15
16impl Span {
17 pub fn new(start: usize, end: usize) -> Self {
18 if start > end {
19 panic!("{start} > {end}");
20 }
21 Self { start, end }
22 }
23
24 pub fn new_with_len(start: usize, len: usize) -> Self {
25 Self {
26 start,
27 end: start + len,
28 }
29 }
30
31 pub fn len(&self) -> usize {
32 self.end - self.start
33 }
34
35 pub fn is_empty(&self) -> bool {
36 self.len() == 0
37 }
38
39 pub fn contains(&self, idx: usize) -> bool {
40 assert!(self.start <= self.end);
41
42 self.start <= idx && idx < self.end
43 }
44
45 pub fn overlaps_with(&self, other: Self) -> bool {
46 (self.start < other.end) && (other.start < self.end)
47 }
48
49 pub fn try_get_content<'a>(&self, source: &'a [char]) -> Option<&'a [char]> {
52 if (self.start > self.end) || (self.start >= source.len()) || (self.end > source.len()) {
53 if self.is_empty() {
54 return Some(&source[0..0]);
55 }
56 return None;
57 }
58
59 Some(&source[self.start..self.end])
60 }
61
62 pub fn expand_to_include(&mut self, target: usize) {
67 if target < self.start {
68 self.start = target;
69 } else if target >= self.end {
70 self.end = target + 1;
71 }
72 }
73
74 pub fn get_content<'a>(&self, source: &'a [char]) -> &'a [char] {
76 match self.try_get_content(source) {
77 Some(v) => v,
78 None => panic!(
79 "Could not get position {:?} within \"{}\"",
80 self,
81 source.to_string()
82 ),
83 }
84 }
85
86 pub fn get_content_string(&self, source: &[char]) -> String {
87 String::from_iter(self.get_content(source))
88 }
89
90 pub fn set_len(&mut self, length: usize) {
91 self.end = self.start + length;
92 }
93
94 pub fn with_len(&self, length: usize) -> Self {
95 let mut cloned = *self;
96 cloned.set_len(length);
97 cloned
98 }
99
100 pub fn push_by(&mut self, by: usize) {
102 self.start += by;
103 self.end += by;
104 }
105
106 pub fn pull_by(&mut self, by: usize) {
108 self.start -= by;
109 self.end -= by;
110 }
111
112 pub fn pushed_by(&self, by: usize) -> Self {
114 let mut clone = *self;
115 clone.start += by;
116 clone.end += by;
117 clone
118 }
119
120 pub fn pulled_by(&self, by: usize) -> Option<Self> {
122 if by > self.start {
123 return None;
124 }
125
126 let mut clone = *self;
127 clone.start -= by;
128 clone.end -= by;
129 Some(clone)
130 }
131
132 pub fn with_offset(&self, by: usize) -> Self {
134 let mut clone = *self;
135 clone.push_by(by);
136 clone
137 }
138}
139
140impl From<Range<usize>> for Span {
141 fn from(value: Range<usize>) -> Self {
142 Self::new(value.start, value.end)
143 }
144}
145
146impl From<Span> for Range<usize> {
147 fn from(value: Span) -> Self {
148 value.start..value.end
149 }
150}
151
152impl IntoIterator for Span {
153 type Item = usize;
154
155 type IntoIter = Range<usize>;
156
157 fn into_iter(self) -> Self::IntoIter {
158 self.start..self.end
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use crate::Span;
165
166 #[test]
167 fn overlaps() {
168 assert!(Span::new(0, 5).overlaps_with(Span::new(3, 6)));
169 assert!(Span::new(0, 5).overlaps_with(Span::new(2, 3)));
170 assert!(Span::new(0, 5).overlaps_with(Span::new(4, 5)));
171 assert!(Span::new(0, 5).overlaps_with(Span::new(4, 4)));
172
173 assert!(!Span::new(0, 3).overlaps_with(Span::new(3, 5)));
174 }
175
176 #[test]
177 fn expands_properly() {
178 let mut span = Span::new(2, 2);
179
180 span.expand_to_include(1);
181 assert_eq!(span, Span::new(1, 2));
182
183 span.expand_to_include(2);
184 assert_eq!(span, Span::new(1, 3));
185 }
186}