1use std::convert::From;
2use std::fmt::{Debug, Display, Error};
3use std::{fmt, io};
4
5use thiserror::Error;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct Position {
13 pub(crate) byte_offset: usize,
14 pub(crate) line_column: Option<(usize, usize)>,
15}
16
17impl Position {
18 pub fn with_offset(offset: usize) -> Self {
21 Position {
22 byte_offset: offset,
23 line_column: None,
24 }
25 }
26
27 pub fn with_text_position(&self, line: usize, column: usize) -> Self {
29 Position {
30 line_column: Some((line, column)),
31 ..*self
32 }
33 }
34
35 pub fn byte_offset(&self) -> usize {
37 self.byte_offset
38 }
39
40 pub fn text_position(&self) -> Option<(usize, usize)> {
42 self.line_column
43 }
44
45 pub fn line(&self) -> Option<usize> {
47 self.line_column.map(|(line, _column)| line)
48 }
49
50 pub fn column(&self) -> Option<usize> {
52 self.line_column.map(|(_line, column)| column)
53 }
54
55 pub fn has_text_position(&self) -> bool {
57 self.line_column.is_some()
58 }
59}
60
61impl Display for Position {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), Error> {
64 match &self.line_column {
65 None => write!(f, "{}", self.byte_offset),
66 Some((line, column)) => {
67 write!(f, "{} ({}:{})", self.byte_offset, line, column)
68 }
69 }
70 }
71}
72
73pub type IonResult<T> = Result<T, IonError>;
75
76#[derive(Debug, Error)]
78pub enum IonError {
79 #[error("{source:?}")]
81 IoError {
82 #[from]
83 source: io::Error,
84 },
85
86 #[error("ran out of input while reading {label} at offset {position}")]
90 Incomplete {
91 label: &'static str,
92 position: Position,
93 },
94
95 #[error("{description}")]
97 EncodingError { description: String },
98
99 #[error("{description}")]
101 DecodingError { description: String },
102
103 #[error(
106 "The user has performed an operation that is not legal in the current state: {operation}"
107 )]
108 IllegalOperation { operation: String },
109}
110
111impl From<fmt::Error> for IonError {
112 fn from(error: Error) -> Self {
113 IonError::EncodingError {
114 description: error.to_string(),
115 }
116 }
117}
118
119impl Clone for IonError {
124 fn clone(&self) -> Self {
125 use IonError::*;
126 match self {
127 IoError { source } => IoError {
128 source: io::Error::from(source.kind()),
130 },
131 Incomplete { label, position } => Incomplete {
132 label,
133 position: position.clone(),
134 },
135 EncodingError { description } => EncodingError {
136 description: description.clone(),
137 },
138 DecodingError { description } => DecodingError {
139 description: description.clone(),
140 },
141 IllegalOperation { operation } => IllegalOperation {
142 operation: operation.clone(),
143 },
144 }
145 }
146}
147
148impl PartialEq for IonError {
152 fn eq(&self, other: &Self) -> bool {
153 use IonError::*;
154 match (self, other) {
155 (IoError { source: s1 }, IoError { source: s2 }) => s1.kind() == s2.kind(),
157 (
158 Incomplete {
159 label: l1,
160 position: p1,
161 },
162 Incomplete {
163 label: l2,
164 position: p2,
165 },
166 ) => l1 == l2 && p1 == p2,
167 (EncodingError { description: s1 }, EncodingError { description: s2 }) => s1 == s2,
168 (DecodingError { description: s1 }, DecodingError { description: s2 }) => s1 == s2,
169 (IllegalOperation { operation: s1 }, IllegalOperation { operation: s2 }) => s1 == s2,
170 _ => false,
171 }
172 }
173}
174
175pub fn incomplete_data_error<T>(label: &'static str, offset: usize) -> IonResult<T> {
176 Err(incomplete_data_error_raw(label, offset))
177}
178
179pub fn incomplete_data_error_raw(label: &'static str, offset: usize) -> IonError {
180 IonError::Incomplete {
181 label,
182 position: Position::with_offset(offset),
183 }
184}
185
186pub fn incomplete_text_error<T>(label: &'static str, position: Position) -> IonResult<T> {
187 Err(incomplete_text_error_raw(label, position))
188}
189
190pub fn incomplete_text_error_raw(label: &'static str, position: Position) -> IonError {
191 IonError::Incomplete { label, position }
192}
193
194pub fn decoding_error<T, S: AsRef<str>>(description: S) -> IonResult<T> {
197 Err(decoding_error_raw(description))
198}
199
200#[inline(never)]
203pub fn decoding_error_raw<S: AsRef<str>>(description: S) -> IonError {
204 IonError::DecodingError {
205 description: description.as_ref().to_string(),
206 }
207}
208
209pub fn encoding_error<T, S: AsRef<str>>(description: S) -> IonResult<T> {
212 Err(encoding_error_raw(description))
213}
214
215#[inline(never)]
218pub fn encoding_error_raw<S: AsRef<str>>(description: S) -> IonError {
219 IonError::EncodingError {
220 description: description.as_ref().to_string(),
221 }
222}
223
224pub fn illegal_operation<T, S: AsRef<str>>(operation: S) -> IonResult<T> {
227 Err(illegal_operation_raw(operation))
228}
229
230#[inline(never)]
233pub fn illegal_operation_raw<S: AsRef<str>>(operation: S) -> IonError {
234 IonError::IllegalOperation {
235 operation: operation.as_ref().to_string(),
236 }
237}