diff options
author | HampusM <hampus@hampusmat.com> | 2023-03-25 17:42:28 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2023-03-25 17:42:28 +0100 |
commit | add06dafdf874b1b419e5eef918c6b1131ab09fd (patch) | |
tree | c1d52d3ece248d96562a3d77beb44973e7720847 /src/deserialization/mod.rs | |
parent | f49d77c2961be28c3cc500af185813dd5e83a367 (diff) |
perf: improve XML deserialization speed
Diffstat (limited to 'src/deserialization/mod.rs')
-rw-r--r-- | src/deserialization/mod.rs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/deserialization/mod.rs b/src/deserialization/mod.rs new file mode 100644 index 0000000..fa25e4b --- /dev/null +++ b/src/deserialization/mod.rs @@ -0,0 +1,124 @@ +use std::error::Error; +use std::ops::Deref; + +use quick_xml::events::{BytesStart, Event}; + +pub mod buffer_deserializer; + +pub trait Deserialize: Sized +{ + type Error: Error + Send + Sync + 'static; + + fn deserialize<TDeserializer: Deserializer>( + start: &BytesStart, + deserializer: &mut TDeserializer, + ) -> Result<Self, Self::Error>; +} + +pub trait Deserializer +{ + fn de_tag<De: Deserialize>( + &mut self, + tag_name: &str, + ignore_end: IgnoreEnd, + ) -> Result<De, DeserializerError>; + + fn de_tag_with<Output, Err, DeserializeFn>( + &mut self, + tag_name: &str, + ignore_end: IgnoreEnd, + deserialize: DeserializeFn, + ) -> Result<Output, DeserializerError> + where + Err: Error + Send + Sync + 'static, + DeserializeFn: FnOnce(&BytesStart, &mut Self) -> Result<Output, Err>; + + fn de_tag_list<De: Deserialize>( + &mut self, + tag_name: &str, + ) -> Result<Vec<De>, DeserializerError>; + + fn de_text(&mut self) -> Result<String, DeserializerError>; + + fn skip_to_tag_start(&mut self, tag_name: &str) -> Result<(), DeserializerError>; + + fn skip_to_tag_end(&mut self, tag_name: &str) -> Result<(), DeserializerError>; +} + +pub enum IgnoreEnd +{ + Yes, + No, +} + +/// Function pointer type passable to [`Deserializer::de_tag_with`]. +pub type DeserializeWithFn<Output, Err, Deserializer> = + fn(&BytesStart, &mut Deserializer) -> Result<Output, Err>; + +#[derive(Debug, thiserror::Error)] +pub enum DeserializerError +{ + #[error("Failed to read")] + ReadFailed(#[from] quick_xml::Error), + + #[error("Failed to deserialize {0}")] + DeserializeFailed(&'static str, #[source] WrappedDeserializeError), + + #[error("Expected {expected_event_name} event. Found {found_event:?}")] + UnexpectedEvent + { + expected_event_name: String, + found_event: Event<'static>, + }, + + #[error("Unexpected end of file")] + UnexpectedEndOfFile, +} + +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct WrappedDeserializeError(Box<dyn Error + Send + Sync>); + +impl WrappedDeserializeError +{ + fn new<Err: Error + Send + Sync + 'static>(err: Err) -> Self + { + Self(Box::new(err)) + } +} + +impl Deref for WrappedDeserializeError +{ + type Target = dyn Error; + + fn deref(&self) -> &Self::Target + { + self.0.as_ref() + } +} + +pub trait ResultExt<Value> +{ + fn try_event(self) -> Result<Option<Value>, DeserializerError>; +} + +impl<Value> ResultExt<Value> for Result<Value, DeserializerError> +{ + fn try_event(self) -> Result<Option<Value>, DeserializerError> + { + self.map_or_else( + |err| { + if let DeserializerError::UnexpectedEvent { + expected_event_name: _, + found_event: _, + } = err + { + return Ok(None); + } + + Err(err) + }, + |value| Ok(Some(value)), + ) + } +} |