1use std::{
2 error, fmt,
3 io::{self},
4 num::TryFromIntError,
5 string,
6};
7
8#[derive(Debug, PartialEq, Eq)]
9pub enum ParseErrorKind {
10 Io,
11 EndOfFile,
12 InvalidInput,
13 Unsupported,
14}
15
16#[derive(Debug)]
17pub struct ParseError {
18 pub kind: ParseErrorKind,
19 pub message: String,
20 pub context: String,
21}
22
23impl ParseError {
24 pub fn new<S: Into<String>>(message: S, kind: ParseErrorKind) -> ParseError {
25 ParseError {
26 message: message.into(),
27 kind,
28 context: String::new(),
29 }
30 }
31
32 pub fn invalid<S: Into<String>>(message: S) -> ParseError {
33 Self::new(message, ParseErrorKind::InvalidInput)
34 }
35
36 pub fn unsupported<S: Into<String>>(message: S) -> ParseError {
37 Self::new(message, ParseErrorKind::Unsupported)
38 }
39
40 pub fn eof<S: Into<String>>(message: S) -> ParseError {
41 Self::new(message, ParseErrorKind::EndOfFile)
42 }
43}
44
45impl error::Error for ParseError {}
46impl fmt::Display for ParseError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(
49 f,
50 "Error while parsing remarkable file {}. {}",
51 self.message,
52 format!("\n{}", self.context)
53 )
54 }
55}
56impl From<io::Error> for ParseError {
57 fn from(error: io::Error) -> Self {
58 match error.kind() {
59 io::ErrorKind::UnexpectedEof => Self::eof(error.to_string()),
60 _ => Self::new(format!("Failed to read input: {error}"), ParseErrorKind::Io),
61 }
62 }
63}
64impl From<TryFromIntError> for ParseError {
65 fn from(error: TryFromIntError) -> Self {
66 Self::new(
67 format!("Failed to read input: {error}"),
68 ParseErrorKind::InvalidInput,
69 )
70 }
71}
72impl From<string::FromUtf8Error> for ParseError {
73 fn from(value: string::FromUtf8Error) -> Self {
74 Self::invalid(format!("Invalid utf-8 string found: '{value}'"))
75 }
76}