use std::num::NonZeroUsize;
use std::num::TryFromIntError;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug)]
pub enum Error {
TryFromInt(TryFromIntError),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::TryFromInt(err) => write!(f, "{err}"),
}
}
}
impl std::error::Error for Error {}
type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Position {
line_no: NonZeroUsize,
col_no: NonZeroUsize,
byte_no: usize,
}
impl Position {
pub fn new(line_no: NonZeroUsize, col_no: NonZeroUsize, byte_no: usize) -> Self {
Self {
line_no,
col_no,
byte_no,
}
}
pub fn try_new(line_no: usize, col_no: usize, byte_no: usize) -> Result<Self> {
let line_no = NonZeroUsize::try_from(line_no).map_err(Error::TryFromInt)?;
let col_no = NonZeroUsize::try_from(col_no).map_err(Error::TryFromInt)?;
Ok(Self {
line_no,
col_no,
byte_no,
})
}
pub fn line_no(&self) -> NonZeroUsize {
self.line_no
}
pub fn col_no(&self) -> NonZeroUsize {
self.col_no
}
pub fn byte_no(&self) -> usize {
self.byte_no
}
}
impl std::fmt::Display for Position {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.line_no, self.col_no)
}
}
impl TryFrom<pest::Position<'_>> for Position {
type Error = Error;
fn try_from(position: pest::Position<'_>) -> Result<Self> {
let (line_no, col_no) = position.line_col();
let line_no = NonZeroUsize::try_from(line_no).map_err(Error::TryFromInt)?;
let col_no = NonZeroUsize::try_from(col_no).map_err(Error::TryFromInt)?;
Ok(Position {
line_no,
col_no,
byte_no: position.pos(),
})
}
}