Skip to content

Commit 616d55b

Browse files
authored
Merge pull request #4 from rust-analyzer/proper-ranges
Proper ranges
2 parents dea4c9c + da93594 commit 616d55b

File tree

2 files changed

+21
-68
lines changed

2 files changed

+21
-68
lines changed

src/range.rs

Lines changed: 20 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use {
22
crate::TextSize,
33
std::{
44
cmp,
5-
convert::{TryFrom, TryInto},
5+
convert::TryInto,
66
fmt,
7-
ops::{Bound, Index, IndexMut, Range, RangeBounds},
7+
ops::{Bound, Index, IndexMut, RangeBounds},
88
},
99
};
1010

@@ -30,21 +30,28 @@ use {
3030
/// † See the note on [`TextRange::len`] for differing behavior for incorrect reverse ranges.
3131
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
3232
pub struct TextRange {
33+
// Invariant: start <= end
3334
start: TextSize,
3435
end: TextSize,
3536
}
3637

37-
#[allow(non_snake_case)]
38-
pub(crate) const fn TextRange(start: TextSize, end: TextSize) -> TextRange {
39-
TextRange { start, end }
40-
}
41-
4238
impl fmt::Debug for TextRange {
4339
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4440
write!(f, "[{}..{})", self.start(), self.end())
4541
}
4642
}
4743

44+
/// Creates a new `TextRange` with given `start` and `end.
45+
///
46+
/// # Panics
47+
///
48+
/// Panics if `end < start`.
49+
#[allow(non_snake_case)]
50+
pub fn TextRange(start: TextSize, end: TextSize) -> TextRange {
51+
assert!(start <= end);
52+
TextRange { start, end }
53+
}
54+
4855
/// Identity methods.
4956
impl TextRange {
5057
/// The start point of this range.
@@ -58,11 +65,6 @@ impl TextRange {
5865
}
5966

6067
/// The size of this range.
61-
///
62-
/// # Panics
63-
///
64-
/// When `end() < start()`, triggers a subtraction overflow.
65-
/// This will panic with debug assertions, and overflow without.
6668
pub const fn len(self) -> TextSize {
6769
// HACK for const fn: math on primitives only
6870
TextSize(self.end().raw - self.start().raw)
@@ -71,11 +73,10 @@ impl TextRange {
7173
/// Check if this range empty or reversed.
7274
///
7375
/// When `end() < start()`, this returns false.
74-
/// Code should prefer `is_empty()` to `len() == 0`,
75-
/// as this safeguards against incorrect reverse ranges.
76+
/// Code should prefer `is_empty()` to `len() == 0`.
7677
pub const fn is_empty(self) -> bool {
7778
// HACK for const fn: math on primitives only
78-
self.start().raw >= self.end().raw
79+
self.start().raw == self.end().raw
7980
}
8081
}
8182

@@ -91,7 +92,10 @@ impl TextRange {
9192
pub fn intersection(lhs: TextRange, rhs: TextRange) -> Option<TextRange> {
9293
let start = cmp::max(lhs.start(), rhs.start());
9394
let end = cmp::min(lhs.end(), rhs.end());
94-
Some(TextRange(start, end)).filter(|_| start <= end)
95+
if end < start {
96+
return None;
97+
}
98+
Some(TextRange(start, end))
9599
}
96100

97101
/// The smallest range that completely contains both ranges.
@@ -145,54 +149,3 @@ impl RangeBounds<TextSize> for TextRange {
145149
Bound::Excluded(&self.end)
146150
}
147151
}
148-
149-
macro_rules! conversions {
150-
(From<$lte:ident> for TextRange) => {
151-
impl From<Range<$lte>> for TextRange {
152-
fn from(value: Range<$lte>) -> TextRange {
153-
TextRange(value.start.into(), value.end.into())
154-
}
155-
}
156-
// Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
157-
};
158-
(TryFrom<$gt:ident> for TextRange) => {
159-
impl TryFrom<Range<$gt>> for TextRange {
160-
type Error = <$gt as TryInto<u32>>::Error;
161-
fn try_from(value: Range<$gt>) -> Result<TextRange, Self::Error> {
162-
Ok(TextRange(value.start.try_into()?, value.end.try_into()?))
163-
}
164-
}
165-
// Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
166-
};
167-
{
168-
lt TextSize [$($lt:ident)*]
169-
eq TextSize [$($eq:ident)*]
170-
gt TextSize [$($gt:ident)*]
171-
varries [$($var:ident)*]
172-
} => {
173-
$(
174-
conversions!(From<$lt> for TextRange);
175-
// unlike TextSize, we do not provide conversions in the "out" direction.
176-
)*
177-
178-
$(
179-
conversions!(From<$eq> for TextRange);
180-
)*
181-
182-
$(
183-
conversions!(TryFrom<$gt> for TextRange);
184-
)*
185-
186-
$(
187-
conversions!(TryFrom<$var> for TextRange);
188-
)*
189-
};
190-
}
191-
192-
// FIXME: when `default impl` is usable, change to blanket impls for [Try]Into<TextSize> instead
193-
conversions! {
194-
lt TextSize [u8 u16]
195-
eq TextSize [u32 TextSize]
196-
gt TextSize [u64]
197-
varries [usize]
198-
}

tests/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ fn size(x: u32) -> TextSize {
55
}
66

77
fn range(x: ops::Range<u32>) -> TextRange {
8-
TextRange::from(x)
8+
TextRange(x.start.into(), x.end.into())
99
}
1010

1111
#[test]

0 commit comments

Comments
 (0)