use std::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum ErrorCode {
Syntax,
InvalidArgument,
UnknownName,
DuplicateName,
SizeMismatch,
Cycle,
LimitExceeded,
DecodeError,
EncodeError,
UnsupportedFormat,
Io,
}
impl ErrorCode {
pub fn as_str(self) -> &'static str {
match self {
ErrorCode::Syntax => "syntax",
ErrorCode::InvalidArgument => "invalid_argument",
ErrorCode::UnknownName => "unknown_name",
ErrorCode::DuplicateName => "duplicate_name",
ErrorCode::SizeMismatch => "size_mismatch",
ErrorCode::Cycle => "cycle",
ErrorCode::LimitExceeded => "limit_exceeded",
ErrorCode::DecodeError => "decode_error",
ErrorCode::EncodeError => "encode_error",
ErrorCode::UnsupportedFormat => "unsupported_format",
ErrorCode::Io => "io",
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Position {
pub(crate) file: u32,
pub line: usize,
pub column: usize,
}
impl Position {
pub fn new(line: usize, column: usize) -> Self {
Self {
file: 0,
line,
column,
}
}
pub(crate) fn in_file(file: u32, line: usize, column: usize) -> Self {
Self { file, line, column }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Error {
pub code: ErrorCode,
pub message: String,
pub position: Option<Position>,
pub file: Option<String>,
}
impl Error {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
position: None,
file: None,
}
}
pub fn at(position: Position, code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
position: Some(position),
file: None,
}
}
pub(crate) fn invalid(message: impl Into<String>) -> Self {
Self::new(ErrorCode::InvalidArgument, message)
}
pub(crate) fn decode(message: impl Into<String>) -> Self {
Self::new(ErrorCode::DecodeError, message)
}
pub(crate) fn limit(message: impl Into<String>) -> Self {
Self::new(ErrorCode::LimitExceeded, message)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(file) = &self.file {
write!(f, "{file}, ")?;
}
match self.position {
Some(p) => write!(f, "line {}, column {}: {}", p.line, p.column, self.message),
None => f.write_str(&self.message),
}
}
}
impl std::error::Error for Error {}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Self::new(ErrorCode::Io, value.to_string())
}
}
pub type Result<T> = std::result::Result<T, Error>;