#[cfg(feature = "serde")]
extern crate serde;
use std::{fmt, iter, ops};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct TextUnit(u32);
impl TextUnit {
#[inline(always)]
pub fn of_char(c: char) -> TextUnit {
TextUnit(c.len_utf8() as u32)
}
#[inline(always)]
pub fn of_str(s: &str) -> TextUnit {
if s.len() > u32::max_value() as usize {
panic!("string is to long")
}
TextUnit(s.len() as u32)
}
#[inline(always)]
pub fn checked_sub(self, other: TextUnit) -> Option<TextUnit> {
self.0.checked_sub(other.0).map(TextUnit)
}
#[inline(always)]
pub fn from_usize(size: usize) -> TextUnit {
#[cfg(debug_assertions)]
{
if size > u32::max_value() as usize {
panic!("overflow when converting to TextUnit: {}", size)
}
}
(size as u32).into()
}
#[inline(always)]
pub fn to_usize(self) -> usize {
u32::from(self) as usize
}
}
impl fmt::Debug for TextUnit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
impl fmt::Display for TextUnit {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<TextUnit> for u32 {
#[inline(always)]
fn from(tu: TextUnit) -> u32 {
tu.0
}
}
impl From<u32> for TextUnit {
#[inline(always)]
fn from(tu: u32) -> TextUnit {
TextUnit(tu)
}
}
macro_rules! unit_ops_impls {
($T:ident, $f:ident, $op:tt, $AT:ident, $af:ident) => {
impl ops::$T<TextUnit> for TextUnit {
type Output = TextUnit;
#[inline(always)]
fn $f(self, rhs: TextUnit) -> TextUnit {
TextUnit(self.0 $op rhs.0)
}
}
impl<'a> ops::$T<&'a TextUnit> for TextUnit {
type Output = TextUnit;
#[inline(always)]
fn $f(self, rhs: &'a TextUnit) -> TextUnit {
ops::$T::$f(self, *rhs)
}
}
impl<'a> ops::$T<TextUnit> for &'a TextUnit {
type Output = TextUnit;
#[inline(always)]
fn $f(self, rhs: TextUnit) -> TextUnit {
ops::$T::$f(*self, rhs)
}
}
impl<'a, 'b> ops::$T<&'a TextUnit> for &'b TextUnit {
type Output = TextUnit;
#[inline(always)]
fn $f(self, rhs: &'a TextUnit) -> TextUnit {
ops::$T::$f(*self, *rhs)
}
}
impl ops::$AT<TextUnit> for TextUnit {
#[inline(always)]
fn $af(&mut self, rhs: TextUnit) {
self.0 = self.0 $op rhs.0
}
}
impl<'a> ops::$AT<&'a TextUnit> for TextUnit {
#[inline(always)]
fn $af(&mut self, rhs: &'a TextUnit) {
ops::$AT::$af(self, *rhs)
}
}
};
}
macro_rules! range_ops_impls {
($T:ident, $f:ident, $op:tt, $AT:ident, $af:ident) => {
impl ops::$T<TextUnit> for TextRange {
type Output = TextRange;
#[inline(always)]
fn $f(self, rhs: TextUnit) -> TextRange {
TextRange::from_to(
self.start() $op rhs,
self.end() $op rhs,
)
}
}
impl<'a> ops::$T<&'a TextUnit> for TextRange {
type Output = TextRange;
#[inline(always)]
fn $f(self, rhs: &'a TextUnit) -> TextRange {
TextRange::from_to(
self.start() $op rhs,
self.end() $op rhs,
)
}
}
impl<'a> ops::$T<TextUnit> for &'a TextRange {
type Output = TextRange;
#[inline(always)]
fn $f(self, rhs: TextUnit) -> TextRange {
TextRange::from_to(
self.start() $op rhs,
self.end() $op rhs,
)
}
}
impl<'a, 'b> ops::$T<&'a TextUnit> for &'b TextRange {
type Output = TextRange;
#[inline(always)]
fn $f(self, rhs: &'a TextUnit) -> TextRange {
TextRange::from_to(
self.start() $op rhs,
self.end() $op rhs,
)
}
}
impl ops::$AT<TextUnit> for TextRange {
#[inline(always)]
fn $af(&mut self, rhs: TextUnit) {
*self = *self $op rhs
}
}
impl<'a> ops::$AT<&'a TextUnit> for TextRange {
#[inline(always)]
fn $af(&mut self, rhs: &'a TextUnit) {
*self = *self $op rhs
}
}
};
}
unit_ops_impls!(Add, add, +, AddAssign, add_assign);
unit_ops_impls!(Sub, sub, -, SubAssign, sub_assign);
range_ops_impls!(Add, add, +, AddAssign, add_assign);
range_ops_impls!(Sub, sub, -, SubAssign, sub_assign);
impl<'a> iter::Sum<&'a TextUnit> for TextUnit {
fn sum<I: Iterator<Item = &'a TextUnit>>(iter: I) -> TextUnit {
iter.fold(TextUnit::from(0), ops::Add::add)
}
}
impl iter::Sum<TextUnit> for TextUnit {
fn sum<I: Iterator<Item = TextUnit>>(iter: I) -> TextUnit {
iter.fold(TextUnit::from(0), ops::Add::add)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct TextRange {
start: TextUnit,
end: TextUnit,
}
impl fmt::Debug for TextRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
impl fmt::Display for TextRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}; {})", self.start(), self.end())
}
}
impl TextRange {
#[inline(always)]
pub fn from_to(from: TextUnit, to: TextUnit) -> TextRange {
assert!(from <= to, "Invalid text range [{}; {})", from, to);
TextRange {
start: from,
end: to,
}
}
#[inline(always)]
pub fn offset_len(offset: TextUnit, len: TextUnit) -> TextRange {
TextRange::from_to(offset, offset + len)
}
#[inline(always)]
pub fn start(&self) -> TextUnit {
self.start
}
#[inline(always)]
pub fn end(&self) -> TextUnit {
self.end
}
#[inline(always)]
pub fn len(&self) -> TextUnit {
self.end - self.start
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.start() == self.end()
}
#[inline(always)]
pub fn is_subrange(&self, other: &TextRange) -> bool {
other.start() <= self.start() && self.end() <= other.end()
}
#[inline(always)]
pub fn checked_sub(self, other: TextUnit) -> Option<TextRange> {
let res = TextRange::offset_len(self.start().checked_sub(other)?, self.len());
Some(res)
}
}
impl ops::RangeBounds<TextUnit> for TextRange {
fn start_bound(&self) -> ops::Bound<&TextUnit> {
ops::Bound::Included(&self.start)
}
fn end_bound(&self) -> ops::Bound<&TextUnit> {
ops::Bound::Excluded(&self.end)
}
}
impl ops::Index<TextRange> for str {
type Output = str;
fn index(&self, index: TextRange) -> &str {
&self[index.start().0 as usize..index.end().0 as usize]
}
}
impl ops::Index<TextRange> for String {
type Output = str;
fn index(&self, index: TextRange) -> &str {
&self.as_str()[index]
}
}
#[cfg(feature = "serde")]
mod serde_impls {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use {TextRange, TextUnit};
impl Serialize for TextUnit {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for TextUnit {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = Deserialize::deserialize(deserializer)?;
Ok(TextUnit(value))
}
}
impl Serialize for TextRange {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
(self.start, self.end).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for TextRange {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let (start, end) = Deserialize::deserialize(deserializer)?;
Ok(TextRange { start, end })
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sum() {
let xs: Vec<TextUnit> = vec![0.into(), 1.into(), 2.into()];
assert_eq!(xs.iter().sum::<TextUnit>(), 3.into());
assert_eq!(xs.into_iter().sum::<TextUnit>(), 3.into());
}
#[test]
fn test_ops() {
let r = TextRange::from_to(10.into(), 20.into());
let u: TextUnit = 5.into();
assert_eq!(r + u, TextRange::from_to(15.into(), 25.into()),);
assert_eq!(r - u, TextRange::from_to(5.into(), 15.into()),);
}
#[test]
fn test_checked_ops() {
let x: TextUnit = 1.into();
assert_eq!(x.checked_sub(1.into()), Some(0.into()));
assert_eq!(x.checked_sub(2.into()), None);
let r = TextRange::from_to(1.into(), 2.into());
assert_eq!(
r.checked_sub(1.into()),
Some(TextRange::from_to(0.into(), 1.into()))
);
assert_eq!(x.checked_sub(2.into()), None);
}
#[test]
fn test_subrange() {
let r1 = TextRange::from_to(2.into(), 4.into());
let r2 = TextRange::from_to(2.into(), 3.into());
let r3 = TextRange::from_to(1.into(), 3.into());
assert!(r2.is_subrange(&r1));
assert!(!r3.is_subrange(&r1));
}
}