use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
pub message: String,
pub offset: usize,
}
impl ParseError {
pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {
ParseError {
message: message.into(),
offset,
}
}
pub fn line(&self, input: &str) -> usize {
let until = self.offset.min(input.len());
1 + input[..until].bytes().filter(|&b| b == b'\n').count()
}
pub fn column(&self, input: &str) -> usize {
let until = self.offset.min(input.len());
let last_newline = input[..until].rfind('\n').map(|p| p + 1).unwrap_or(0);
until - last_newline + 1
}
pub fn snippet<'a>(&self, input: &'a str) -> &'a str {
let len = input.len();
let offset = self.offset.min(len);
let raw_start = offset.saturating_sub(20);
let start = (raw_start..=offset)
.find(|&i| input.is_char_boundary(i))
.unwrap_or(0);
let raw_end = (offset + 40).min(len);
let end = (offset..=raw_end)
.rev()
.find(|&i| input.is_char_boundary(i))
.unwrap_or(offset);
&input[start..end]
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"parse error at byte offset {}: {}",
self.offset, self.message
)
}
}
impl std::error::Error for ParseError {}