1use kparse::{Code, TokenizerError};
6use nom_locate::LocatedSpan;
7use std::error::Error;
8use std::fmt::{Debug, Display, Formatter};
9use std::str::from_utf8;
10
11pub(crate) trait AsStatic<T: ?Sized> {
14 fn as_static(&self) -> &'static T;
15}
16
17pub type OdsResult<T> = Result<T, OdsError>;
19
20#[derive(Debug)]
21#[allow(missing_docs)]
22pub enum OdsError {
23 Ods(String),
24 Io(std::io::Error),
25 Zip(zip::result::ZipError),
26 Xml(quick_xml::Error),
27 XmlAttr(quick_xml::events::attributes::AttrError),
28 Utf8(std::str::Utf8Error),
29 Parse(&'static str, Option<String>),
30 ParseInt(std::num::ParseIntError),
31 ParseBool(std::str::ParseBoolError),
32 ParseFloat(std::num::ParseFloatError),
33 Chrono(chrono::format::ParseError),
34 SystemTime(std::time::SystemTimeError),
35 Base64(base64::DecodeError),
36}
37
38impl Display for OdsError {
39 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
40 match self {
41 OdsError::Ods(e) => write!(f, "Ods {}", e)?,
42 OdsError::Io(e) => write!(f, "IO {}", e)?,
43 OdsError::Zip(e) => write!(f, "Zip {:?}", e)?,
44 OdsError::Xml(e) => write!(f, "Xml {}", e)?,
45 OdsError::XmlAttr(e) => write!(f, "Xml attribute {}", e)?,
46 OdsError::Parse(e, v) => write!(f, "Parse {} {:?}", e, v)?,
47 OdsError::ParseInt(e) => write!(f, "ParseInt {}", e)?,
48 OdsError::ParseBool(e) => write!(f, "ParseBool {}", e)?,
49 OdsError::ParseFloat(e) => write!(f, "ParseFloat {}", e)?,
50 OdsError::Chrono(e) => write!(f, "Chrono {}", e)?,
51 OdsError::SystemTime(e) => write!(f, "SystemTime {}", e)?,
52 OdsError::Utf8(e) => write!(f, "UTF8 {}", e)?,
53 OdsError::Base64(e) => write!(f, "Base64 {}", e)?,
54 }
55
56 Ok(())
57 }
58}
59
60impl Error for OdsError {
61 fn cause(&self) -> Option<&dyn Error> {
62 match self {
63 OdsError::Ods(_) => None,
64 OdsError::Io(e) => Some(e),
65 OdsError::Zip(e) => Some(e),
66 OdsError::Xml(e) => Some(e),
67 OdsError::XmlAttr(e) => Some(e),
68 OdsError::Parse(_, _) => None,
69 OdsError::ParseInt(e) => Some(e),
70 OdsError::ParseBool(e) => Some(e),
71 OdsError::ParseFloat(e) => Some(e),
72 OdsError::Chrono(e) => Some(e),
73 OdsError::SystemTime(e) => Some(e),
74 OdsError::Utf8(e) => Some(e),
75 OdsError::Base64(e) => Some(e),
76 }
77 }
78}
79
80impl From<std::io::Error> for OdsError {
81 fn from(err: std::io::Error) -> OdsError {
82 OdsError::Io(err)
83 }
84}
85
86impl From<zip::result::ZipError> for OdsError {
87 fn from(err: zip::result::ZipError) -> OdsError {
88 OdsError::Zip(err)
89 }
90}
91
92impl From<quick_xml::Error> for OdsError {
93 fn from(err: quick_xml::Error) -> OdsError {
94 OdsError::Xml(err)
95 }
96}
97
98impl From<quick_xml::events::attributes::AttrError> for OdsError {
99 fn from(err: quick_xml::events::attributes::AttrError) -> OdsError {
100 OdsError::XmlAttr(err)
101 }
102}
103
104impl From<std::str::ParseBoolError> for OdsError {
105 fn from(err: std::str::ParseBoolError) -> OdsError {
106 OdsError::ParseBool(err)
107 }
108}
109
110impl From<std::num::ParseIntError> for OdsError {
111 fn from(err: std::num::ParseIntError) -> OdsError {
112 OdsError::ParseInt(err)
113 }
114}
115
116impl From<std::num::ParseFloatError> for OdsError {
117 fn from(err: std::num::ParseFloatError) -> OdsError {
118 OdsError::ParseFloat(err)
119 }
120}
121
122impl From<chrono::format::ParseError> for OdsError {
123 fn from(err: chrono::format::ParseError) -> OdsError {
124 OdsError::Chrono(err)
125 }
126}
127
128impl From<std::time::SystemTimeError> for OdsError {
129 fn from(err: std::time::SystemTimeError) -> OdsError {
130 OdsError::SystemTime(err)
131 }
132}
133
134impl From<std::str::Utf8Error> for OdsError {
135 fn from(err: std::str::Utf8Error) -> OdsError {
136 OdsError::Utf8(err)
137 }
138}
139
140impl From<base64::DecodeError> for OdsError {
141 fn from(err: base64::DecodeError) -> OdsError {
142 OdsError::Base64(err)
143 }
144}
145
146impl<C> From<nom::Err<TokenizerError<C, &[u8]>>> for OdsError
147where
148 C: AsStatic<str>,
149{
150 fn from(value: nom::Err<TokenizerError<C, &[u8]>>) -> Self {
151 match value {
152 nom::Err::Incomplete(_) => OdsError::Parse("incomplete", None),
153 nom::Err::Error(e) | nom::Err::Failure(e) => OdsError::Parse(
154 e.code.as_static(),
155 Some(String::from_utf8_lossy(e.span).into()),
156 ),
157 }
158 }
159}
160
161impl<C> From<nom::Err<TokenizerError<C, &str>>> for OdsError
162where
163 C: AsStatic<str>,
164{
165 fn from(value: nom::Err<TokenizerError<C, &str>>) -> Self {
166 match value {
167 nom::Err::Incomplete(_) => OdsError::Parse("incomplete", None),
168 nom::Err::Error(e) | nom::Err::Failure(e) => {
169 OdsError::Parse(e.code.as_static(), Some(e.span.into()))
170 }
171 }
172 }
173}
174
175impl<'s, C, X> From<nom::Err<TokenizerError<C, LocatedSpan<&'s str, X>>>> for OdsError
176where
177 C: Code + AsStatic<str>,
178{
179 fn from(value: nom::Err<TokenizerError<C, LocatedSpan<&'s str, X>>>) -> Self {
180 match value {
181 nom::Err::Incomplete(_) => OdsError::Parse("incomplete", None),
182 nom::Err::Error(e) | nom::Err::Failure(e) => {
183 OdsError::Parse(e.code.as_static(), Some((*e.span).into()))
184 }
185 }
186 }
187}
188
189impl<'s, C, X> From<nom::Err<TokenizerError<C, LocatedSpan<&'s [u8], X>>>> for OdsError
190where
191 C: Code + AsStatic<str>,
192{
193 fn from(value: nom::Err<TokenizerError<C, LocatedSpan<&'s [u8], X>>>) -> Self {
194 match value {
195 nom::Err::Incomplete(_) => OdsError::Parse("incomplete", None),
196 nom::Err::Error(e) | nom::Err::Failure(e) => OdsError::Parse(
197 e.code.as_static(),
198 Some(from_utf8(*e.span).unwrap_or("decoding failed").into()),
199 ),
200 }
201 }
202}