Skip to main content

beancount_parser/
error.rs

1#![allow(clippy::module_name_repetitions)]
2#![allow(deprecated)]
3#![allow(unused_assignments)]
4
5use std::{
6    fmt::{Debug, Display},
7    io,
8    path::PathBuf,
9};
10
11#[cfg(feature = "miette")]
12use miette::{Diagnostic, SourceSpan};
13
14use crate::Span;
15
16/// Error returned in case of invalid beancount syntax found
17///
18/// # Example
19/// ```
20/// # use beancount_parser::BeancountFile;
21/// let result: Result<BeancountFile<f64>, beancount_parser::Error> = "2022-05-21 oops".parse();
22/// assert!(result.is_err());
23/// let error = result.unwrap_err();
24/// assert_eq!(error.line_number(), 1);
25/// ```
26#[derive(Clone)]
27#[cfg_attr(feature = "miette", derive(Diagnostic))]
28pub struct Error {
29    #[cfg(feature = "miette")]
30    #[source_code]
31    src: String,
32    #[cfg(feature = "miette")]
33    #[label]
34    span: SourceSpan,
35    line_number: u32,
36}
37
38impl Debug for Error {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        f.debug_struct("Error")
41            .field("line_number", &self.line_number())
42            .finish()
43    }
44}
45
46impl Display for Error {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        write!(f, "Invalid beancount syntax at line: {}", self.line_number)
49    }
50}
51
52impl std::error::Error for Error {}
53
54impl Error {
55    #[cfg(not(feature = "miette"))]
56    pub(crate) fn new(_: impl Into<String>, span: Span<'_>) -> Self {
57        Self {
58            line_number: span.location_line(),
59        }
60    }
61
62    #[cfg(feature = "miette")]
63    pub(crate) fn new(src: impl Into<String>, span: Span<'_>) -> Self {
64        Self {
65            src: src.into(),
66            span: span.location_offset().into(),
67            line_number: span.location_line(),
68        }
69    }
70
71    /// Line number at which the error was found in the input
72    #[must_use]
73    pub fn line_number(&self) -> u32 {
74        self.line_number
75    }
76}
77
78/// Error returned when reading a beancount file from disk
79#[allow(missing_docs)]
80#[derive(Debug)]
81pub struct ReadFileErrorV2 {
82    path: PathBuf,
83    pub(crate) error: ReadFileErrorContent,
84}
85
86impl ReadFileErrorV2 {
87    pub(crate) fn from_io(path: PathBuf, err: io::Error) -> Self {
88        Self {
89            path,
90            error: ReadFileErrorContent::Io(err),
91        }
92    }
93
94    pub(crate) fn from_syntax(path: PathBuf, err: Error) -> Self {
95        Self {
96            path,
97            error: ReadFileErrorContent::Syntax(err),
98        }
99    }
100}
101
102impl Display for ReadFileErrorV2 {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        match &self.error {
105            ReadFileErrorContent::Io(err) => {
106                write!(f, "Cannot read {}: {}", self.path.display(), err)
107            }
108            ReadFileErrorContent::Syntax(err) => {
109                write!(f, "Invalid syntax in {}: {}", self.path.display(), err)
110            }
111        }
112    }
113}
114
115impl std::error::Error for ReadFileErrorV2 {}
116
117/// Content of the error returned when reading a beancount file from disk
118#[allow(missing_docs)]
119#[derive(Debug)]
120pub(crate) enum ReadFileErrorContent {
121    Io(std::io::Error),
122    Syntax(Error),
123}
124
125/// Content of the error returned when reading a beancount file from disk
126#[allow(missing_docs)]
127#[derive(Debug)]
128#[cfg_attr(feature = "miette", derive(Diagnostic))]
129#[deprecated(since = "2.4.0", note = "use `ReadFileErrorV2 instead`")]
130pub enum ReadFileError {
131    Io(std::io::Error),
132    Syntax(Error),
133}
134
135impl From<std::io::Error> for ReadFileError {
136    fn from(value: std::io::Error) -> Self {
137        Self::Io(value)
138    }
139}
140
141impl From<Error> for ReadFileError {
142    fn from(value: Error) -> Self {
143        Self::Syntax(value)
144    }
145}
146
147impl Display for ReadFileError {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        match self {
150            ReadFileError::Io(_) => write!(f, "IO error"),
151            ReadFileError::Syntax(_) => write!(f, "Syntax error"),
152        }
153    }
154}
155
156impl std::error::Error for ReadFileError {}
157
158/// Error that may be returned by the various `TryFrom`/`TryInto` implementation
159/// to signify that the value cannot be converted to the desired type
160#[derive(Debug, Clone)]
161#[non_exhaustive]
162pub struct ConversionError;
163
164impl Display for ConversionError {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        write!(f, "Cannot convert to the desired type")
167    }
168}
169
170impl std::error::Error for ConversionError {}