use std::fmt;
use facet::Facet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RangeError {
ReversedByteRange {
start: ByteOffset,
end: ByteOffset,
},
ReversedPointRange {
start: PointBytes,
end: PointBytes,
},
}
impl fmt::Display for RangeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ReversedByteRange { start, end } => {
write!(
f,
"byte range end {} is before start {}",
end.get(),
start.get()
)
}
Self::ReversedPointRange { start, end } => {
write!(
f,
"point range end {}:{} is before start {}:{}",
end.row.get(),
end.column.get(),
start.row.get(),
start.column.get()
)
}
}
}
}
impl std::error::Error for RangeError {}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ByteOffset(u32);
impl ByteOffset {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn get(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq)]
pub struct ByteRange {
start: ByteOffset,
end: ByteOffset,
}
impl ByteRange {
pub fn new(start: ByteOffset, end: ByteOffset) -> Result<Self, RangeError> {
if end < start {
return Err(RangeError::ReversedByteRange { start, end });
}
Ok(Self { start, end })
}
pub const fn start(self) -> ByteOffset {
self.start
}
pub const fn end(self) -> ByteOffset {
self.end
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Row(u32);
impl Row {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn get(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Utf8ColumnBytes(u32);
impl Utf8ColumnBytes {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn get(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq, PartialOrd, Ord)]
pub struct PointBytes {
row: Row,
column: Utf8ColumnBytes,
}
impl PointBytes {
pub const fn new(row: Row, column: Utf8ColumnBytes) -> Self {
Self { row, column }
}
pub const fn row(self) -> Row {
self.row
}
pub const fn column(self) -> Utf8ColumnBytes {
self.column
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq)]
pub struct PointRange {
start: PointBytes,
end: PointBytes,
}
impl PointRange {
pub fn new(start: PointBytes, end: PointBytes) -> Result<Self, RangeError> {
if end < start {
return Err(RangeError::ReversedPointRange { start, end });
}
Ok(Self { start, end })
}
pub const fn start(self) -> PointBytes {
self.start
}
pub const fn end(self) -> PointBytes {
self.end
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq)]
pub struct InputEdit {
old_bytes: ByteRange,
new_end_byte: ByteOffset,
old_points: PointRange,
new_end_point: PointBytes,
}
impl InputEdit {
pub const fn new(
old_bytes: ByteRange,
new_end_byte: ByteOffset,
old_points: PointRange,
new_end_point: PointBytes,
) -> Self {
Self {
old_bytes,
new_end_byte,
old_points,
new_end_point,
}
}
pub const fn old_bytes(self) -> ByteRange {
self.old_bytes
}
pub const fn new_end_byte(self) -> ByteOffset {
self.new_end_byte
}
pub const fn old_points(self) -> PointRange {
self.old_points
}
pub const fn new_end_point(self) -> PointBytes {
self.new_end_point
}
}
#[derive(Debug, Clone, Copy, Facet, PartialEq, Eq)]
pub struct IncludedRange {
bytes: ByteRange,
points: PointRange,
}
impl IncludedRange {
pub const fn new(bytes: ByteRange, points: PointRange) -> Self {
Self { bytes, points }
}
pub const fn bytes(self) -> ByteRange {
self.bytes
}
pub const fn points(self) -> PointRange {
self.points
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn byte_ranges_reject_reversed_order() {
let start = ByteOffset::new(10);
let end = ByteOffset::new(5);
assert_eq!(
ByteRange::new(start, end),
Err(RangeError::ReversedByteRange { start, end })
);
}
#[test]
fn point_ranges_reject_reversed_order() {
let start = PointBytes::new(Row::new(2), Utf8ColumnBytes::new(0));
let end = PointBytes::new(Row::new(1), Utf8ColumnBytes::new(20));
assert_eq!(
PointRange::new(start, end),
Err(RangeError::ReversedPointRange { start, end })
);
}
}