|
2 | 2 | crate::TextSize,
|
3 | 3 | std::{
|
4 | 4 | cmp, fmt,
|
5 |
| - ops::{Bound, Index, IndexMut, Range, RangeBounds}, |
| 5 | + ops::{Add, AddAssign, Bound, Index, IndexMut, Range, RangeBounds, Sub, SubAssign}, |
6 | 6 | },
|
7 | 7 | };
|
8 | 8 |
|
@@ -133,6 +133,38 @@ impl TextRange {
|
133 | 133 | let end = cmp::max(lhs.end(), rhs.end());
|
134 | 134 | TextRange(start, end)
|
135 | 135 | }
|
| 136 | + |
| 137 | + /// Add an offset to this range. |
| 138 | + /// |
| 139 | + /// Note that this is not appropriate for changing where a `TextRange` is |
| 140 | + /// within some string; rather, it is for changing the reference anchor |
| 141 | + /// that the `TextRange` is measured against. |
| 142 | + /// |
| 143 | + /// The unchecked version (`Add::add`) will _always_ panic on overflow, |
| 144 | + /// in contrast to primitive integers, which check in debug mode only. |
| 145 | + #[inline] |
| 146 | + pub fn checked_add(self, offset: TextSize) -> Option<TextRange> { |
| 147 | + Some(TextRange { |
| 148 | + start: self.start.checked_add(offset)?, |
| 149 | + end: self.end.checked_add(offset)?, |
| 150 | + }) |
| 151 | + } |
| 152 | + |
| 153 | + /// Subtract an offset from this range. |
| 154 | + /// |
| 155 | + /// Note that this is not appropriate for changing where a `TextRange` is |
| 156 | + /// within some string; rather, it is for changing the reference anchor |
| 157 | + /// that the `TextRange` is measured against. |
| 158 | + /// |
| 159 | + /// The unchecked version (`Sub::sub`) will _always_ panic on overflow, |
| 160 | + /// in contrast to primitive integers, which check in debug mode only. |
| 161 | + #[inline] |
| 162 | + pub fn checked_sub(self, offset: TextSize) -> Option<TextRange> { |
| 163 | + Some(TextRange { |
| 164 | + start: self.start.checked_sub(offset)?, |
| 165 | + end: self.end.checked_sub(offset)?, |
| 166 | + }) |
| 167 | + } |
136 | 168 | }
|
137 | 169 |
|
138 | 170 | impl Index<TextRange> for str {
|
@@ -169,3 +201,66 @@ where
|
169 | 201 | r.start().into()..r.end().into()
|
170 | 202 | }
|
171 | 203 | }
|
| 204 | + |
| 205 | +macro_rules! ops { |
| 206 | + (impl $Op:ident for TextRange by fn $f:ident = $op:tt) => { |
| 207 | + impl $Op<&TextSize> for TextRange { |
| 208 | + type Output = TextRange; |
| 209 | + #[inline] |
| 210 | + fn $f(self, other: &TextSize) -> TextRange { |
| 211 | + self $op *other |
| 212 | + } |
| 213 | + } |
| 214 | + impl<T> $Op<T> for &TextRange |
| 215 | + where |
| 216 | + TextRange: $Op<T, Output=TextRange>, |
| 217 | + { |
| 218 | + type Output = TextRange; |
| 219 | + #[inline] |
| 220 | + fn $f(self, other: T) -> TextRange { |
| 221 | + *self $op other |
| 222 | + } |
| 223 | + } |
| 224 | + }; |
| 225 | +} |
| 226 | + |
| 227 | +impl Add<TextSize> for TextRange { |
| 228 | + type Output = TextRange; |
| 229 | + #[inline] |
| 230 | + fn add(self, offset: TextSize) -> TextRange { |
| 231 | + self.checked_add(offset) |
| 232 | + .expect("TextRange +offset overflowed") |
| 233 | + } |
| 234 | +} |
| 235 | + |
| 236 | +impl Sub<TextSize> for TextRange { |
| 237 | + type Output = TextRange; |
| 238 | + #[inline] |
| 239 | + fn sub(self, offset: TextSize) -> TextRange { |
| 240 | + self.checked_sub(offset) |
| 241 | + .expect("TextRange -offset overflowed") |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +ops!(impl Add for TextRange by fn add = +); |
| 246 | +ops!(impl Sub for TextRange by fn sub = -); |
| 247 | + |
| 248 | +impl<A> AddAssign<A> for TextRange |
| 249 | +where |
| 250 | + TextRange: Add<A, Output = TextRange>, |
| 251 | +{ |
| 252 | + #[inline] |
| 253 | + fn add_assign(&mut self, rhs: A) { |
| 254 | + *self = *self + rhs |
| 255 | + } |
| 256 | +} |
| 257 | + |
| 258 | +impl<S> SubAssign<S> for TextRange |
| 259 | +where |
| 260 | + TextRange: Sub<S, Output = TextRange>, |
| 261 | +{ |
| 262 | + #[inline] |
| 263 | + fn sub_assign(&mut self, rhs: S) { |
| 264 | + *self = *self - rhs |
| 265 | + } |
| 266 | +} |
0 commit comments