use std::fmt;
use cirru_parser::Cirru;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Position {
pub line: usize,
pub column: usize,
pub offset: usize,
}
impl Position {
pub fn new(line: usize, column: usize, offset: usize) -> Self {
Position { line, column, offset }
}
pub fn at_offset(offset: usize) -> Self {
Position {
line: 0,
column: 0,
offset,
}
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.line > 0 {
write!(
f,
"at line {}, column {} (byte {})",
self.line, self.column, self.offset
)
} else {
write!(f, "at byte {}", self.offset)
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EdnError {
ParseError {
original: String,
},
StructureError {
message: String,
path: Vec<usize>,
node_preview: Option<String>,
},
ValueError {
message: String,
path: Vec<usize>,
node_preview: Option<String>,
},
DeserializationError {
message: String,
position: Option<Vec<u8>>, },
}
impl EdnError {
pub fn from_parse_error_detailed(err: cirru_parser::CirruError, source: &str) -> Self {
EdnError::ParseError {
original: err.format_detailed(Some(source)),
}
}
pub fn from_parse_error(err: cirru_parser::CirruError) -> Self {
EdnError::ParseError {
original: err.format_detailed(None),
}
}
pub fn structure(message: impl Into<String>, path: Vec<usize>, node: Option<&Cirru>) -> Self {
let node_preview = node.and_then(|n| {
cirru_parser::format_expr_one_liner(n).ok()
});
EdnError::StructureError {
message: message.into(),
path,
node_preview,
}
}
pub fn value(message: impl Into<String>, path: Vec<usize>, node: Option<&Cirru>) -> Self {
let node_preview = node.and_then(|n| {
cirru_parser::format_expr_one_liner(n).ok()
});
EdnError::ValueError {
message: message.into(),
path,
node_preview,
}
}
pub fn deserialization(message: impl Into<String>, position: Option<Vec<u8>>) -> Self {
EdnError::DeserializationError {
message: message.into(),
position,
}
}
pub fn message(&self) -> &str {
match self {
EdnError::ParseError { original } => original,
EdnError::StructureError { message, .. } => message,
EdnError::ValueError { message, .. } => message,
EdnError::DeserializationError { message, .. } => message,
}
}
}
impl fmt::Display for EdnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EdnError::ParseError { original } => {
write!(f, "Parse error:\n{original}")
}
EdnError::StructureError {
message,
path,
node_preview,
} => {
write!(f, "Structure error")?;
if !path.is_empty() {
write!(f, " at {path:?}")?;
}
write!(f, ": {message}")?;
if let Some(preview) = node_preview {
write!(f, "\n Node: {preview}")?;
}
Ok(())
}
EdnError::ValueError {
message,
path,
node_preview,
} => {
write!(f, "Value error")?;
if !path.is_empty() {
write!(f, " at {path:?}")?;
}
write!(f, ": {message}")?;
if let Some(preview) = node_preview {
write!(f, "\n Node: {preview}")?;
}
Ok(())
}
EdnError::DeserializationError { message, .. } => {
write!(f, "Deserialization error: {message}")
}
}
}
}
impl From<&str> for EdnError {
fn from(message: &str) -> Self {
EdnError::ParseError {
original: message.to_string(),
}
}
}
impl From<cirru_parser::CirruError> for EdnError {
fn from(err: cirru_parser::CirruError) -> Self {
EdnError::from_parse_error(err)
}
}
pub type EdnResult<T> = Result<T, EdnError>;