aboutsummaryrefslogtreecommitdiff
path: root/src/deserialization/mod.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-03-25 17:42:28 +0100
committerHampusM <hampus@hampusmat.com>2023-03-25 17:42:28 +0100
commitadd06dafdf874b1b419e5eef918c6b1131ab09fd (patch)
treec1d52d3ece248d96562a3d77beb44973e7720847 /src/deserialization/mod.rs
parentf49d77c2961be28c3cc500af185813dd5e83a367 (diff)
perf: improve XML deserialization speed
Diffstat (limited to 'src/deserialization/mod.rs')
-rw-r--r--src/deserialization/mod.rs124
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)),
+ )
+ }
+}