Unnamed repository; edit this file 'description' to name the repository.
Merge pull request rust-analyzer/text-size#4 from rust-analyzer/proper-ranges
Proper ranges
Aleksey Kladov 2020-03-09
parent 72aef8c · parent 7d86273 · commit 18ba8f5
-rw-r--r--lib/text-size/src/range.rs87
-rw-r--r--lib/text-size/tests/main.rs2
2 files changed, 21 insertions, 68 deletions
diff --git a/lib/text-size/src/range.rs b/lib/text-size/src/range.rs
index fe227cdaff..7e01b12e9f 100644
--- a/lib/text-size/src/range.rs
+++ b/lib/text-size/src/range.rs
@@ -2,9 +2,9 @@ use {
crate::TextSize,
std::{
cmp,
- convert::{TryFrom, TryInto},
+ convert::TryInto,
fmt,
- ops::{Bound, Index, IndexMut, Range, RangeBounds},
+ ops::{Bound, Index, IndexMut, RangeBounds},
},
};
@@ -30,21 +30,28 @@ use {
/// † See the note on [`TextRange::len`] for differing behavior for incorrect reverse ranges.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct TextRange {
+ // Invariant: start <= end
start: TextSize,
end: TextSize,
}
-#[allow(non_snake_case)]
-pub(crate) const fn TextRange(start: TextSize, end: TextSize) -> TextRange {
- TextRange { start, end }
-}
-
impl fmt::Debug for TextRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}..{})", self.start(), self.end())
}
}
+/// Creates a new `TextRange` with given `start` and `end.
+///
+/// # Panics
+///
+/// Panics if `end < start`.
+#[allow(non_snake_case)]
+pub fn TextRange(start: TextSize, end: TextSize) -> TextRange {
+ assert!(start <= end);
+ TextRange { start, end }
+}
+
/// Identity methods.
impl TextRange {
/// The start point of this range.
@@ -58,11 +65,6 @@ impl TextRange {
}
/// The size of this range.
- ///
- /// # Panics
- ///
- /// When `end() < start()`, triggers a subtraction overflow.
- /// This will panic with debug assertions, and overflow without.
pub const fn len(self) -> TextSize {
// HACK for const fn: math on primitives only
TextSize(self.end().raw - self.start().raw)
@@ -71,11 +73,10 @@ impl TextRange {
/// Check if this range empty or reversed.
///
/// When `end() < start()`, this returns false.
- /// Code should prefer `is_empty()` to `len() == 0`,
- /// as this safeguards against incorrect reverse ranges.
+ /// Code should prefer `is_empty()` to `len() == 0`.
pub const fn is_empty(self) -> bool {
// HACK for const fn: math on primitives only
- self.start().raw >= self.end().raw
+ self.start().raw == self.end().raw
}
}
@@ -91,7 +92,10 @@ impl TextRange {
pub fn intersection(lhs: TextRange, rhs: TextRange) -> Option<TextRange> {
let start = cmp::max(lhs.start(), rhs.start());
let end = cmp::min(lhs.end(), rhs.end());
- Some(TextRange(start, end)).filter(|_| start <= end)
+ if end < start {
+ return None;
+ }
+ Some(TextRange(start, end))
}
/// The smallest range that completely contains both ranges.
@@ -145,54 +149,3 @@ impl RangeBounds<TextSize> for TextRange {
Bound::Excluded(&self.end)
}
}
-
-macro_rules! conversions {
- (From<$lte:ident> for TextRange) => {
- impl From<Range<$lte>> for TextRange {
- fn from(value: Range<$lte>) -> TextRange {
- TextRange(value.start.into(), value.end.into())
- }
- }
- // Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
- };
- (TryFrom<$gt:ident> for TextRange) => {
- impl TryFrom<Range<$gt>> for TextRange {
- type Error = <$gt as TryInto<u32>>::Error;
- fn try_from(value: Range<$gt>) -> Result<TextRange, Self::Error> {
- Ok(TextRange(value.start.try_into()?, value.end.try_into()?))
- }
- }
- // Just support `start..end` for now, not `..end`, `start..=end`, `..=end`.
- };
- {
- lt TextSize [$($lt:ident)*]
- eq TextSize [$($eq:ident)*]
- gt TextSize [$($gt:ident)*]
- varries [$($var:ident)*]
- } => {
- $(
- conversions!(From<$lt> for TextRange);
- // unlike TextSize, we do not provide conversions in the "out" direction.
- )*
-
- $(
- conversions!(From<$eq> for TextRange);
- )*
-
- $(
- conversions!(TryFrom<$gt> for TextRange);
- )*
-
- $(
- conversions!(TryFrom<$var> for TextRange);
- )*
- };
-}
-
-// FIXME: when `default impl` is usable, change to blanket impls for [Try]Into<TextSize> instead
-conversions! {
- lt TextSize [u8 u16]
- eq TextSize [u32 TextSize]
- gt TextSize [u64]
- varries [usize]
-}
diff --git a/lib/text-size/tests/main.rs b/lib/text-size/tests/main.rs
index 3288c27320..9a20cf9819 100644
--- a/lib/text-size/tests/main.rs
+++ b/lib/text-size/tests/main.rs
@@ -5,7 +5,7 @@ fn size(x: u32) -> TextSize {
}
fn range(x: ops::Range<u32>) -> TextRange {
- TextRange::from(x)
+ TextRange(x.start.into(), x.end.into())
}
#[test]