use std::fmt;
use std::num::NonZeroUsize;
use text_size::TextSize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidOneBasedCoordinate {
value: usize,
}
impl InvalidOneBasedCoordinate {
#[must_use]
pub const fn value(self) -> usize {
self.value
}
}
impl fmt::Display for InvalidOneBasedCoordinate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "1-based coordinate value must be non-zero")
}
}
impl std::error::Error for InvalidOneBasedCoordinate {}
macro_rules! define_zero_based_coordinate {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct $name(usize);
impl $name {
#[must_use]
pub const fn new(value: usize) -> Self {
Self(value)
}
#[must_use]
pub const fn get(self) -> usize {
self.0
}
}
impl From<$name> for usize {
fn from(value: $name) -> Self {
value.get()
}
}
impl From<usize> for $name {
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({})", stringify!($name), self.0)
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
};
}
macro_rules! define_one_based_coordinate {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct $name(NonZeroUsize);
impl $name {
#[must_use]
pub const fn try_new(value: usize) -> Option<Self> {
match NonZeroUsize::new(value) {
Some(v) => Some(Self(v)),
None => None,
}
}
#[must_use]
pub const fn new(value: usize) -> Self {
match NonZeroUsize::new(value) {
Some(v) => Self(v),
None => panic!("1-based coordinates must be non-zero"),
}
}
#[must_use]
pub const fn get(self) -> usize {
self.0.get()
}
}
impl From<$name> for usize {
fn from(value: $name) -> Self {
value.get()
}
}
impl TryFrom<usize> for $name {
type Error = InvalidOneBasedCoordinate;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Self::try_new(value).ok_or(InvalidOneBasedCoordinate { value })
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({})", stringify!($name), self.0)
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
};
}
define_one_based_coordinate!(
LineNumber
);
define_one_based_coordinate!(
ByteColumn
);
define_one_based_coordinate!(
CharColumn
);
define_zero_based_coordinate!(
ByteOffset
);
define_zero_based_coordinate!(
Utf16Offset
);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Utf16Range {
start: Utf16Offset,
end: Utf16Offset,
}
impl Utf16Range {
#[must_use]
pub const fn new(start: Utf16Offset, end: Utf16Offset) -> Self {
Self { start, end }
}
#[must_use]
pub const fn start(self) -> Utf16Offset {
self.start
}
#[must_use]
pub const fn end(self) -> Utf16Offset {
self.end
}
}
impl From<TextSize> for ByteOffset {
fn from(offset: TextSize) -> Self {
Self::new(usize::from(offset))
}
}
impl TryFrom<ByteOffset> for TextSize {
type Error = std::num::TryFromIntError;
fn try_from(offset: ByteOffset) -> Result<Self, Self::Error> {
Self::try_from(offset.get())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ByteLineCol {
pub line: LineNumber,
pub column: ByteColumn,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CharLineCol {
pub line: LineNumber,
pub column: CharColumn,
}