diff options
Diffstat (limited to 'src/deserializer/mod.rs')
-rw-r--r-- | src/deserializer/mod.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/deserializer/mod.rs b/src/deserializer/mod.rs new file mode 100644 index 0000000..bd0c0e4 --- /dev/null +++ b/src/deserializer/mod.rs @@ -0,0 +1,179 @@ +//! Deserializer. +use std::convert::Infallible; + +use crate::tagged::TagStart; +use crate::DeserializeTagged; + +pub mod buffered; + +/// XML deserializer. +pub trait Deserializer +{ + /// Deserializes a tagged element. + /// + /// # Errors + /// Returns `Err` if deserialization fails. + fn de_tag<De: DeserializeTagged>( + &mut self, + tag_name: &str, + ignore_end: IgnoreEnd, + ) -> Result<De, Error<De::Error>>; + + /// Deserializes a tagged element using the given function. + /// + /// # Errors + /// Returns `Err` if deserialization fails. + fn de_tag_with<Output, Err, DeserializeFn>( + &mut self, + tag_name: &str, + ignore_end: IgnoreEnd, + deserialize: DeserializeFn, + ) -> Result<Output, Error<Err>> + where + Err: std::error::Error + Send + Sync + 'static, + DeserializeFn: FnOnce(&TagStart, &mut Self) -> Result<Output, Err>; + + /// Deserializes a list of tagged elements. + /// + /// # Errors + /// Returns `Err` if deserialization fails. + fn de_tag_list<De: DeserializeTagged>( + &mut self, + tag_name: Option<&str>, + ) -> Result<Vec<De>, Error<De::Error>>; + + /// Deserializes a text element. + /// + /// # Errors + /// Returns `Err` if deserialization fails. + fn de_text(&mut self) -> Result<String, Error<Infallible>>; + + /// Skips past all elements until a tagged element with the name `tag_name` is + /// reached. + /// + /// # Errors + /// Returns `Err` if unsuccessful. + fn skip_to_tag_start(&mut self, tag_name: &str) -> Result<(), Error<Infallible>>; + + /// Skips past all elements until the end of a tagged element with the name `tag_name` + /// is reached. + /// + /// # Errors + /// Returns `Err` if unsuccessful. + fn skip_to_tag_end(&mut self, tag_name: &str) -> Result<(), Error<Infallible>>; +} + +/// Whether or not to skip the end tag of a tagged element. +/// +/// **Should be `No`**. +#[derive(Debug, Default)] +pub enum IgnoreEnd +{ + /// Skip the end tag. + /// + /// **Will cause problems in most cases and should be used very carefully**. + Yes, + + /// Don't skip the end tag. + #[default] + No, +} + +/// [`Deserializer`] error. +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error<DeError> +{ + /// A XML error occurred. + #[error("A XML error occurred")] + XMLError(#[source] XMLError), + + /// Failed to deserialize. + #[error("Failed to deserialize")] + DeserializeFailed(#[from] DeError), + + /// Unexpected event. + #[error("Expected {expected_event_name} event. Found {found_event}")] + UnexpectedEvent + { + /// The name of the expected event. + expected_event_name: String, + + /// The found event. + found_event: String, + }, + + /// Unexpected end of file. + #[error("Unexpected end of file")] + UnexpectedEndOfFile, +} + +impl<DeError> Error<DeError> +{ + /// Returns `Self` with `DeError` as [`Infallible`]. + /// + /// # Panics + /// Will panic if `Self` is the `DeserializeFailed` variant. + pub fn into_never_de_err(self) -> Error<Infallible> + { + match self { + Self::XMLError(xml_err) => Error::XMLError(xml_err), + Self::DeserializeFailed(_) => { + panic!("is a deserialization error"); + } + Self::UnexpectedEvent { + expected_event_name, + found_event, + } => Error::UnexpectedEvent { + expected_event_name, + found_event, + }, + Self::UnexpectedEndOfFile => Error::UnexpectedEndOfFile, + } + } +} + +impl Error<Infallible> +{ + fn into_with_de_error<DeError>(self) -> Error<DeError> + { + match self { + Self::XMLError(xml_err) => Error::XMLError(xml_err), + Self::DeserializeFailed(_) => { + unreachable!(); + } + Self::UnexpectedEvent { + expected_event_name, + found_event, + } => Error::UnexpectedEvent { + expected_event_name, + found_event, + }, + Self::UnexpectedEndOfFile => Error::UnexpectedEndOfFile, + } + } +} + +impl From<Error<Error<Infallible>>> for Error<Infallible> +{ + fn from(err: Error<Error<Infallible>>) -> Self + { + match err { + Error::XMLError(xml_err) => Self::XMLError(xml_err), + Error::DeserializeFailed(de_err) => de_err, + Error::UnexpectedEvent { + expected_event_name, + found_event, + } => Self::UnexpectedEvent { + expected_event_name, + found_event, + }, + Error::UnexpectedEndOfFile => Self::UnexpectedEndOfFile, + } + } +} + +/// XML error. +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct XMLError(#[from] quick_xml::Error); |