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
| -rw-r--r-- | lib/text-size/src/range.rs | 87 | ||||
| -rw-r--r-- | lib/text-size/tests/main.rs | 2 |
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] |