#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)]
pub struct TextRange {
pub start: usize,
pub end: usize,
}
impl TextRange {
pub const fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
pub const fn cursor(position: usize) -> Self {
Self {
start: position,
end: position,
}
}
pub const fn zero() -> Self {
Self { start: 0, end: 0 }
}
pub const fn collapsed(&self) -> bool {
self.start == self.end
}
pub fn length(&self) -> usize {
self.end.abs_diff(self.start)
}
pub fn min(&self) -> usize {
self.start.min(self.end)
}
pub fn max(&self) -> usize {
self.start.max(self.end)
}
pub fn contains(&self, index: usize) -> bool {
index >= self.min() && index < self.max()
}
pub fn coerce_in(&self, max: usize) -> Self {
Self {
start: self.start.min(max),
end: self.end.min(max),
}
}
pub const fn all(length: usize) -> Self {
Self {
start: 0,
end: length,
}
}
pub fn safe_slice<'a>(&self, text: &'a str) -> &'a str {
if text.is_empty() {
return "";
}
let start = self.min().min(text.len());
let end = self.max().min(text.len());
let start = text.floor_char_boundary(start);
let end = text.ceil_char_boundary(end);
if start <= end { &text[start..end] } else { "" }
}
}
#[cfg(test)]
#[path = "tests/range_tests.rs"]
mod tests;