Make TextRange constructors more boring

Remove `fn TextRange(` as that's slightly unusual and surprising,
which will add up to a lot of confusion over the long run.

Instead add:

* `new` as the biased, canonical way to create range from bounds
* `from_len` as an alternative ctor from starting position and len
* `empty` for empty ranges at a given offset
* `up_to` for ranges at zero offset with given length
* `default` for an empty range at zero
This commit is contained in:
Aleksey Kladov 2020-03-21 09:15:28 +01:00
parent c69d303414
commit 8d9a1a4192
6 changed files with 41 additions and 41 deletions

View File

@ -10,18 +10,18 @@ use {
///
/// # Translation from `text_unit`
///
/// - `TextRange::from_to(from, to)` ⟹ `TextRange(from, to)`
/// - `TextRange::offset_len(offset, size)` ⟹ `TextRange::up_to(size) + offset`
/// - `TextRange::from_to(from, to)` ⟹ `TextRange::new(from, to)`
/// - `TextRange::offset_len(offset, size)` ⟹ `TextRange::from_len(offset, size)`
/// - `range.start()` ⟹ `range.start()`
/// - `range.end()` ⟹ `range.end()`
/// - `range.len()` ⟹ `range.len()`
/// - `range.is_empty()` ⟹ `range.is_empty()`
/// - `a.is_subrange(b)` ⟹ `b.contains_range(a)`
/// - `a.intersection(b)` ⟹ `TextRange::intersection(a, b)`
/// - `a.extend_to(b)` ⟹ `TextRange::covering(a, b)`
/// - `a.intersection(b)` ⟹ `a.intersect(b)`
/// - `a.extend_to(b)` ⟹ `a.cover(b)`
/// - `range.contains(offset)` ⟹ `range.contains(point)`
/// - `range.contains_inclusive(offset)` ⟹ `range.contains_inclusive(point)`
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct TextRange {
// Invariant: start <= end
start: TextSize,
@ -34,19 +34,24 @@ impl fmt::Debug for TextRange {
}
}
/// Creates a new `TextRange` with the given `start` and `end` (`start..end`).
///
/// # Panics
///
/// Panics if `end < start`.
#[allow(non_snake_case)]
#[inline]
pub fn TextRange(start: TextSize, end: TextSize) -> TextRange {
assert!(start <= end);
TextRange { start, end }
}
impl TextRange {
/// Creates a new `TextRange` with the given `start` and `end` (`start..end`).
///
/// # Panics
///
/// Panics if `end < start`.
#[inline]
pub fn new(start: TextSize, end: TextSize) -> TextRange {
assert!(start <= end);
TextRange { start, end }
}
/// Create a new `TextRange` with the given `start` and `len` (`start..start + len`).
#[inline]
pub fn from_len(start: TextSize, len: TextSize) -> TextRange {
TextRange::new(start, start + len)
}
/// Create a zero-length range at the specified offset (`offset..offset`).
#[inline]
pub const fn empty(offset: TextSize) -> TextRange {
@ -59,10 +64,8 @@ impl TextRange {
/// Create a range up to the given end (`..end`).
#[inline]
pub const fn up_to(end: TextSize) -> TextRange {
TextRange {
start: TextSize::zero(),
end,
}
let start = TextSize::zero();
TextRange { start, end }
}
}
@ -84,7 +87,9 @@ impl TextRange {
#[inline]
pub const fn len(self) -> TextSize {
// HACK for const fn: math on primitives only
TextSize(self.end().raw - self.start().raw)
TextSize {
raw: self.end().raw - self.start().raw,
}
}
/// Check if this range is empty.
@ -124,14 +129,14 @@ impl TextRange {
if end < start {
return None;
}
Some(TextRange(start, end))
Some(TextRange::new(start, end))
}
/// Extends the range to cover `other` as well.
pub fn cover(self, other: TextRange) -> TextRange {
let start = cmp::min(self.start(), other.start());
let end = cmp::max(self.end(), other.end());
TextRange(start, end)
TextRange::new(start, end)
}
/// Extends the range to cover `other` offsets as well.

View File

@ -17,7 +17,7 @@ impl<'de> Deserialize<'de> for TextSize {
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(TextSize)
u32::deserialize(deserializer).map(TextSize::from)
}
}
@ -43,6 +43,6 @@ impl<'de> Deserialize<'de> for TextRange {
start, end
)));
}
Ok(TextRange(start, end))
Ok(TextRange::new(start, end))
}
}

View File

@ -33,11 +33,6 @@ pub struct TextSize {
pub(crate) raw: u32,
}
#[allow(non_snake_case)]
pub(crate) const fn TextSize(raw: u32) -> TextSize {
TextSize { raw }
}
impl fmt::Debug for TextSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.raw)
@ -57,7 +52,7 @@ impl TextSize {
/// but is more explicit on intent.
#[inline]
pub const fn zero() -> TextSize {
TextSize(0)
TextSize { raw: 0 }
}
}
@ -65,27 +60,27 @@ impl TextSize {
// Last updated for parity with Rust 1.42.0.
impl TextSize {
/// The smallest representable text size. (`u32::MIN`)
pub const MIN: TextSize = TextSize(u32::MIN);
pub const MIN: TextSize = TextSize { raw: u32::MIN };
/// The largest representable text size. (`u32::MAX`)
pub const MAX: TextSize = TextSize(u32::MAX);
pub const MAX: TextSize = TextSize { raw: u32::MAX };
/// Checked addition. Returns `None` if overflow occurred.
#[inline]
pub fn checked_add(self, rhs: TextSize) -> Option<TextSize> {
self.raw.checked_add(rhs.raw).map(TextSize)
self.raw.checked_add(rhs.raw).map(|raw| TextSize { raw })
}
/// Checked subtraction. Returns `None` if overflow occurred.
#[inline]
pub fn checked_sub(self, rhs: TextSize) -> Option<TextSize> {
self.raw.checked_sub(rhs.raw).map(TextSize)
self.raw.checked_sub(rhs.raw).map(|raw| TextSize { raw })
}
}
impl From<u32> for TextSize {
#[inline]
fn from(raw: u32) -> Self {
TextSize(raw)
TextSize { raw }
}
}
@ -117,7 +112,7 @@ macro_rules! ops {
type Output = TextSize;
#[inline]
fn $f(self, other: TextSize) -> TextSize {
TextSize(self.raw $op other.raw)
TextSize { raw: self.raw $op other.raw }
}
}
impl $Op<&TextSize> for TextSize {

View File

@ -18,6 +18,6 @@ impl TextSized for &'_ str {
impl TextSized for char {
#[inline]
fn text_size(self) -> TextSize {
TextSize(self.len_utf8() as u32)
(self.len_utf8() as u32).into()
}
}

View File

@ -5,7 +5,7 @@ fn size(x: u32) -> TextSize {
}
fn range(x: ops::Range<u32>) -> TextRange {
TextRange(x.start.into(), x.end.into())
TextRange::new(x.start.into(), x.end.into())
}
#[test]

View File

@ -5,7 +5,7 @@ fn size(x: u32) -> TextSize {
}
fn range(x: ops::Range<u32>) -> TextRange {
TextRange(x.start.into(), x.end.into())
TextRange::new(x.start.into(), x.end.into())
}
#[test]