xml_stinks/deserializer/mod.rs
1//! Deserializer.
2use std::convert::Infallible;
3
4use crate::tagged::TagStart;
5use crate::util::{feature_alternate, trait_alias};
6use crate::DeserializeTagged;
7
8pub mod buffered;
9
10/// XML deserializer.
11pub trait Deserializer
12{
13 /// Deserializes a tagged element.
14 ///
15 /// # Errors
16 /// Returns `Err` if deserialization fails.
17 fn de_tag<De: DeserializeTagged>(
18 &mut self,
19 tag_name: &str,
20 ignore_end: IgnoreEnd,
21 ) -> Result<De, Error<De::Error>>;
22
23 /// Deserializes a tagged element using the given function.
24 ///
25 /// # Errors
26 /// Returns `Err` if deserialization fails.
27 fn de_tag_with<Output, Err, Func>(
28 &mut self,
29 tag_name: &str,
30 ignore_end: IgnoreEnd,
31 deserialize: Func,
32 ) -> Result<Output, Error<Err>>
33 where
34 Output: MaybeStatic,
35 Err: std::error::Error + Send + Sync + 'static,
36 Func: FnOnce(&TagStart, &mut Self) -> Result<Output, Err> + MaybeStatic;
37
38 /// Deserializes a list of tagged elements.
39 ///
40 /// # Errors
41 /// Returns `Err` if deserialization fails.
42 fn de_tag_list<De, TagName>(
43 &mut self,
44 tag_name: Option<TagName>,
45 ) -> Result<Vec<De>, Error<De::Error>>
46 where
47 De: DeserializeTagged,
48 TagName: AsRef<str> + MaybeStatic;
49
50 /// Deserializes a text element.
51 ///
52 /// # Errors
53 /// Returns `Err` if deserialization fails.
54 fn de_text(&mut self) -> Result<String, Error<Infallible>>;
55
56 /// Skips past all elements until a tagged element with the name `tag_name` is
57 /// reached.
58 ///
59 /// # Errors
60 /// Returns `Err` if unsuccessful.
61 fn skip_to_tag_start(&mut self, tag_name: &str) -> Result<(), Error<Infallible>>;
62
63 /// Skips past all elements until the end of a tagged element with the name `tag_name`
64 /// is reached.
65 ///
66 /// # Errors
67 /// Returns `Err` if unsuccessful.
68 fn skip_to_tag_end(&mut self, tag_name: &str) -> Result<(), Error<Infallible>>;
69}
70
71trait_alias!(
72 bounds_when_feature = "deserializer-static-generics",
73 /// Bound to `'static` if the `deserializer-static-generics` feature is enabled.
74 pub MaybeStatic: 'static;
75);
76
77/// Whether or not to skip the end tag of a tagged element.
78///
79/// **Should be `No`**.
80#[derive(Debug, Default, PartialEq, Eq)]
81pub enum IgnoreEnd
82{
83 /// Skip the end tag.
84 ///
85 /// **Will cause problems in most cases and should be used very carefully**.
86 Yes,
87
88 /// Don't skip the end tag.
89 #[default]
90 No,
91}
92
93/// [`Deserializer`] error.
94#[derive(Debug, thiserror::Error)]
95#[non_exhaustive]
96pub enum Error<DeError>
97{
98 /// A XML error occurred.
99 #[error("A XML error occurred")]
100 XMLError(#[source] XMLError),
101
102 /// Failed to deserialize.
103 #[error("Failed to deserialize")]
104 DeserializeFailed(#[from] DeError),
105
106 /// Unexpected event.
107 #[error("Expected {expected_event_name} event. Found {found_event}")]
108 UnexpectedEvent
109 {
110 /// The name of the expected event.
111 expected_event_name: String,
112
113 /// The found event.
114 found_event: String,
115 },
116
117 /// Unexpected end of file.
118 #[error("Unexpected end of file")]
119 UnexpectedEndOfFile,
120}
121
122impl<DeError> Error<DeError>
123{
124 /// Returns `Self` with `DeError` as [`Infallible`].
125 ///
126 /// # Panics
127 /// Will panic if `Self` is the `DeserializeFailed` variant.
128 pub fn into_never_de_err(self) -> Error<Infallible>
129 {
130 match self {
131 Self::XMLError(xml_err) => Error::XMLError(xml_err),
132 Self::DeserializeFailed(_) => {
133 panic!("is a deserialization error");
134 }
135 Self::UnexpectedEvent {
136 expected_event_name,
137 found_event,
138 } => Error::UnexpectedEvent {
139 expected_event_name,
140 found_event,
141 },
142 Self::UnexpectedEndOfFile => Error::UnexpectedEndOfFile,
143 }
144 }
145}
146
147impl Error<Infallible>
148{
149 fn into_with_de_error<DeError>(self) -> Error<DeError>
150 {
151 match self {
152 Self::XMLError(xml_err) => Error::XMLError(xml_err),
153 Self::DeserializeFailed(_) => {
154 unreachable!();
155 }
156 Self::UnexpectedEvent {
157 expected_event_name,
158 found_event,
159 } => Error::UnexpectedEvent {
160 expected_event_name,
161 found_event,
162 },
163 Self::UnexpectedEndOfFile => Error::UnexpectedEndOfFile,
164 }
165 }
166}
167
168impl From<Error<Error<Infallible>>> for Error<Infallible>
169{
170 fn from(err: Error<Error<Infallible>>) -> Self
171 {
172 match err {
173 Error::XMLError(xml_err) => Self::XMLError(xml_err),
174 Error::DeserializeFailed(de_err) => de_err,
175 Error::UnexpectedEvent {
176 expected_event_name,
177 found_event,
178 } => Self::UnexpectedEvent {
179 expected_event_name,
180 found_event,
181 },
182 Error::UnexpectedEndOfFile => Self::UnexpectedEndOfFile,
183 }
184 }
185}
186
187impl<DeError> Error<DeError>
188{
189 /// Converts `Self` into `Err`.
190 pub fn into_error<Err>(self) -> Err
191 where
192 Err: From<DeError> + From<Error<Infallible>>,
193 {
194 if let Error::DeserializeFailed(de_err) = self {
195 return de_err.into();
196 }
197
198 self.into_never_de_err().into()
199 }
200}
201
202/// XML error.
203#[derive(Debug, thiserror::Error)]
204#[error(transparent)]
205pub struct XMLError(#[from] quick_xml::Error);
206
207/// Implements conversion from [`Error`] with [`From`] for the given error type.
208///
209/// Allows for custom error types with source error types to easily be converted into with
210/// `?`.
211///
212/// The given error type should implement `From<Error<Infallible>>`.
213///
214/// # Examples
215/// ```
216/// use std::convert::Infallible;
217///
218/// use xml_stinks::deserializer::Error as DeserializerError;
219/// use xml_stinks::impl_from_deserializer_error;
220///
221/// #[derive(Debug, thiserror::Error)]
222/// enum FooError
223/// {
224/// #[error("Deserialization failed")]
225/// DeserializeFailed(#[from] DeserializerError<Infallible>),
226///
227/// #[error("Invalid bar")]
228/// InvalidBar(#[from] BarError),
229/// }
230///
231/// impl_from_deserializer_error!(FooError);
232///
233/// #[derive(Debug, thiserror::Error)]
234/// enum BarError
235/// {
236/// #[error("Oops")]
237/// Oops,
238/// }
239///
240/// let err_a: FooError = DeserializerError::<Infallible>::UnexpectedEndOfFile.into();
241///
242/// assert!(matches!(
243/// err_a,
244/// FooError::DeserializeFailed(DeserializerError::UnexpectedEndOfFile)
245/// ));
246///
247/// let err_b: FooError = DeserializerError::DeserializeFailed(BarError::Oops).into();
248///
249/// assert!(matches!(err_b, FooError::InvalidBar(BarError::Oops)));
250/// ```
251#[macro_export]
252macro_rules! impl_from_deserializer_error {
253 ($err: path) => {
254 impl<DeError: Into<Self>> From<::xml_stinks::deserializer::Error<DeError>>
255 for $err
256 {
257 fn from(err: ::xml_stinks::deserializer::Error<DeError>) -> Self
258 {
259 if let ::xml_stinks::deserializer::Error::DeserializeFailed(de_err) = err
260 {
261 return de_err.into();
262 }
263
264 err.into_never_de_err().into()
265 }
266 }
267 };
268}
269
270feature_alternate!(
271 feature = "deserializer-static-generics",
272 /// Conditional compilation based on whether or not the `deserializer-static-generics`
273 /// feature is enabled.
274 ///
275 /// # Examples
276 /// ```
277 /// use std::io::Cursor;
278 ///
279 /// use xml_stinks::xml_stinks_if_deserializer_static_generics;
280 /// use xml_stinks::deserializer::buffered::Buffered as BufferedDeserializer;
281 /// use xml_stinks::deserializer::Deserializer;
282 ///
283 /// fn do_something(bytes: &[u8])
284 /// {
285 /// let deserializer = xml_stinks_if_deserializer_static_generics!(then {
286 /// BufferedDeserializer::new(Cursor::new(bytes.to_vec()));
287 /// } else {
288 /// // This wouldn't compile if the deserializer-static-generics feature was
289 /// // enabled
290 /// BufferedDeserializer::new(bytes);
291 /// });
292 ///
293 /// // ...
294 /// }
295 /// ```
296 when_enabled =
297 #[macro_export]
298 macro_rules! xml_stinks_if_deserializer_static_generics {
299 (then { $($then: tt)* }$(else { $($else: tt)* })?) => {
300 $($then)*
301 };
302 },
303 when_disabled =
304 #[macro_export]
305 macro_rules! xml_stinks_if_deserializer_static_generics {
306 (then { $($then: tt)* }$(else { $($else: tt)* })?) => {
307 $($($else)*)?
308 };
309 }
310);