1#![no_std]
2
3use core::{cmp::Ordering, ops::Range};
4
5#[cfg(feature = "span-value-usize")]
6pub type SpanValue = usize;
8#[cfg(feature = "span-value-u128")]
9pub type SpanValue = u128;
11#[cfg(feature = "span-value-u64")]
12pub type SpanValue = u64;
14#[cfg(feature = "span-value-u32")]
15pub type SpanValue = u32;
17#[cfg(feature = "span-value-u16")]
18pub type SpanValue = u16;
20#[cfg(feature = "span-value-u8")]
21pub type SpanValue = u8;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
26pub struct Span {
27 pub start: SpanValue,
29 pub end: SpanValue,
31}
32
33impl Span {
34 #[inline(always)]
36 pub fn new() -> Self {
37 Self::new_from(0, 0)
38 }
39
40 #[inline(always)]
42 pub fn new_from(start: SpanValue, end: SpanValue) -> Self {
43 Span { start, end }
44 }
45
46 #[inline(always)]
48 pub fn grow_front(&mut self, amount: SpanValue) {
49 self.end += amount;
50 }
51
52 #[inline(always)]
54 pub fn with_grow_front(&self, amount: SpanValue) -> Self {
55 let mut new = *self;
56 new.end += amount;
57 new
58 }
59
60 #[inline(always)]
65 pub fn grow_back(&mut self, amount: SpanValue) {
66 assert!(
67 self.start >= amount,
68 "cannot create a span with a negative start value"
69 );
70 self.start -= amount;
71 }
72
73 #[inline(always)]
78 pub fn with_grow_back(&self, amount: SpanValue) -> Self {
79 assert!(
80 self.start >= amount,
81 "cannot create a span with a negative start value"
82 );
83 let mut new = *self;
84 new.start -= amount;
85 new
86 }
87
88 #[inline(always)]
93 pub fn shrink_back(&mut self, amount: SpanValue) {
94 assert!(self.len() >= amount, "cannot create negative-size span");
95 self.start += amount;
96 }
97
98 #[inline(always)]
103 pub fn with_shrink_back(&self, amount: SpanValue) -> Self {
104 assert!(self.len() >= amount, "cannot create negative-size span");
105 let mut new = *self;
106 new.start += amount;
107 new
108 }
109
110 #[inline(always)]
115 pub fn shrink_front(&mut self, amount: SpanValue) {
116 assert!(self.len() >= amount, "cannot create negative-size span");
117 self.end -= amount;
118 }
119
120 #[inline(always)]
125 pub fn with_shrink_front(&self, amount: SpanValue) -> Self {
126 assert!(self.len() >= amount, "cannot create negative-size span");
127 let mut new = *self;
128 new.end -= amount;
129 new
130 }
131
132 #[inline(always)]
134 pub fn is_empty(&self) -> bool {
135 self.len() == 0
136 }
137
138 #[inline(always)]
140 pub fn len(&self) -> SpanValue {
141 self.end - self.start
142 }
143
144 #[inline(always)]
147 pub fn reset(&mut self) -> Self {
148 let span = *self;
149 self.start = self.end;
150 span
151 }
152
153 #[allow(clippy::unnecessary_cast)]
158 pub fn apply<'a>(&self, string: &'a str) -> &'a str {
159 assert!(
160 string.len() >= self.end as usize,
161 "string is too short to have the span applied"
162 );
163 let start = string
164 .char_indices()
165 .map(|x| x.0)
166 .nth(self.start as usize)
167 .unwrap();
168 let end = string
169 .char_indices()
170 .map(|x| x.0)
171 .nth(self.end as usize)
172 .unwrap_or(string.len());
173 &string[start..end]
174 }
175}
176
177impl From<Span> for Range<SpanValue> {
178 #[inline(always)]
179 fn from(val: Span) -> Self {
180 val.start..val.end
181 }
182}
183
184impl From<Range<SpanValue>> for Span {
185 #[inline(always)]
186 fn from(value: Range<SpanValue>) -> Self {
187 Self::new_from(value.start, value.end)
188 }
189}
190
191impl PartialOrd for Span {
192 #[inline(always)]
193 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
194 dual_order(self.start.cmp(&other.start), self.end.cmp(&other.end))
195 }
196}
197
198fn dual_order(x: Ordering, y: Ordering) -> Option<Ordering> {
199 match (x, y) {
200 (x, y) if x == y => Some(x),
201 (Ordering::Greater, Ordering::Less) | (Ordering::Less, Ordering::Greater) => None,
202 (x, Ordering::Equal) => Some(x),
203 (Ordering::Equal, x) => Some(x),
204 _ => unreachable!(),
205 }
206}