#![allow(clippy::collapsible_if)]
#![allow(clippy::inline_always)]
#![allow(clippy::needless_return)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::type_complexity)]
extern crate smallvec;
extern crate str_indices;
mod crlf;
mod rope;
mod rope_builder;
mod slice;
mod tree;
pub mod iter;
pub mod str_utils;
use std::ops::Bound;
pub use crate::rope::Rope;
pub use crate::rope_builder::RopeBuilder;
pub use crate::slice::RopeSlice;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy)]
#[non_exhaustive]
pub enum Error {
ByteIndexOutOfBounds(usize, usize),
CharIndexOutOfBounds(usize, usize),
LineIndexOutOfBounds(usize, usize),
Utf16IndexOutOfBounds(usize, usize),
ByteIndexNotCharBoundary(usize),
ByteRangeNotCharBoundary(
Option<usize>, Option<usize>, ),
ByteRangeInvalid(
usize, usize, ),
CharRangeInvalid(
usize, usize, ),
ByteRangeOutOfBounds(
Option<usize>, Option<usize>, usize, ),
CharRangeOutOfBounds(
Option<usize>, Option<usize>, usize, ),
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
fn description(&self) -> &str {
""
}
fn cause(&self) -> Option<&dyn std::error::Error> {
None
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Error::ByteIndexOutOfBounds(index, len) => {
write!(
f,
"Byte index out of bounds: byte index {}, Rope/RopeSlice byte length {}",
index, len
)
}
Error::CharIndexOutOfBounds(index, len) => {
write!(
f,
"Char index out of bounds: char index {}, Rope/RopeSlice char length {}",
index, len
)
}
Error::LineIndexOutOfBounds(index, len) => {
write!(
f,
"Line index out of bounds: line index {}, Rope/RopeSlice line count {}",
index, len
)
}
Error::Utf16IndexOutOfBounds(index, len) => {
write!(f, "Utf16 code-unit index out of bounds: utf16 index {}, Rope/RopeSlice utf16 length {}", index, len)
}
Error::ByteIndexNotCharBoundary(index) => {
write!(
f,
"Byte index is not a valid char boundary: byte index {}",
index
)
}
Error::ByteRangeNotCharBoundary(start_idx_opt, end_idx_opt) => {
write!(f, "Byte range does not align with char boundaries: range ")?;
write_range(f, start_idx_opt, end_idx_opt)
}
Error::ByteRangeInvalid(start_idx, end_idx) => {
write!(
f,
"Invalid byte range {}..{}: start must be <= end",
start_idx, end_idx
)
}
Error::CharRangeInvalid(start_idx, end_idx) => {
write!(
f,
"Invalid char range {}..{}: start must be <= end",
start_idx, end_idx
)
}
Error::ByteRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
write!(f, "Byte range out of bounds: byte range ")?;
write_range(f, start_idx_opt, end_idx_opt)?;
write!(f, ", Rope/RopeSlice byte length {}", len)
}
Error::CharRangeOutOfBounds(start_idx_opt, end_idx_opt, len) => {
write!(f, "Char range out of bounds: char range ")?;
write_range(f, start_idx_opt, end_idx_opt)?;
write!(f, ", Rope/RopeSlice char length {}", len)
}
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
fn write_range(
f: &mut std::fmt::Formatter<'_>,
start_idx: Option<usize>,
end_idx: Option<usize>,
) -> std::fmt::Result {
match (start_idx, end_idx) {
(None, None) => {
write!(f, "..")
}
(Some(start), None) => {
write!(f, "{}..", start)
}
(None, Some(end)) => {
write!(f, "..{}", end)
}
(Some(start), Some(end)) => {
write!(f, "{}..{}", start, end)
}
}
}
#[inline(always)]
pub(crate) fn start_bound_to_num(b: Bound<&usize>) -> Option<usize> {
match b {
Bound::Included(n) => Some(*n),
Bound::Excluded(n) => Some(*n + 1),
Bound::Unbounded => None,
}
}
#[inline(always)]
pub(crate) fn end_bound_to_num(b: Bound<&usize>) -> Option<usize> {
match b {
Bound::Included(n) => Some(*n + 1),
Bound::Excluded(n) => Some(*n),
Bound::Unbounded => None,
}
}