aboutsummaryrefslogtreecommitdiff
path: root/src/deserialization/buffer_deserializer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/deserialization/buffer_deserializer.rs')
-rw-r--r--src/deserialization/buffer_deserializer.rs210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/deserialization/buffer_deserializer.rs b/src/deserialization/buffer_deserializer.rs
new file mode 100644
index 0000000..652e1ff
--- /dev/null
+++ b/src/deserialization/buffer_deserializer.rs
@@ -0,0 +1,210 @@
+use std::any::type_name;
+use std::error::Error;
+use std::io::BufRead;
+
+use quick_xml::events::{BytesStart, Event};
+use quick_xml::Reader;
+
+use crate::deserialization::{
+ Deserialize,
+ Deserializer,
+ DeserializerError,
+ IgnoreEnd,
+ WrappedDeserializeError,
+};
+
+macro_rules! read_event {
+ ($self: ident) => {{
+ let event = if let Some(leftover_event) = $self.leftover_event.take() {
+ leftover_event
+ } else {
+ $self.reader.read_event_into(&mut $self.buf)?.into_owned()
+ };
+
+ if let Event::Eof = &event {
+ return Err(DeserializerError::UnexpectedEndOfFile);
+ }
+
+ event
+ }};
+}
+
+pub struct BufferDeserializer<Source>
+{
+ reader: Reader<Source>,
+ leftover_event: Option<Event<'static>>,
+ buf: Vec<u8>,
+}
+
+impl<Source> BufferDeserializer<Source>
+where
+ Source: BufRead,
+{
+ pub fn new(source: Source) -> Self
+ {
+ let mut reader = Reader::from_reader(source);
+
+ reader.trim_text(true);
+ reader.expand_empty_elements(true);
+
+ Self {
+ reader,
+ leftover_event: None,
+ buf: Vec::new(),
+ }
+ }
+}
+
+impl<Source> Deserializer for BufferDeserializer<Source>
+where
+ Source: BufRead,
+{
+ fn de_tag<De: Deserialize>(
+ &mut self,
+ tag_name: &str,
+ ignore_end: IgnoreEnd,
+ ) -> Result<De, DeserializerError>
+ {
+ self.de_tag_with(tag_name, ignore_end, De::deserialize)
+ }
+
+ 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>,
+ {
+ let deserialized = match read_event!(self) {
+ Event::Start(start) if start.name().as_ref() == tag_name.as_bytes() => {
+ deserialize(&start, self).map_err(|err| {
+ DeserializerError::DeserializeFailed(
+ type_name::<Output>(),
+ WrappedDeserializeError::new(err),
+ )
+ })?
+ }
+ event => {
+ self.leftover_event = Some(event.clone().into_owned());
+
+ return Err(DeserializerError::UnexpectedEvent {
+ expected_event_name: format!("start({tag_name})"),
+ found_event: event,
+ });
+ }
+ };
+
+ if let IgnoreEnd::No = ignore_end {
+ self.read_end_event(tag_name)?;
+ }
+
+ Ok(deserialized)
+ }
+
+ fn de_tag_list<De: Deserialize>(
+ &mut self,
+ tag_name: &str,
+ ) -> Result<Vec<De>, DeserializerError>
+ {
+ let mut deserialized_items = Vec::new();
+
+ loop {
+ let start = match read_event!(self) {
+ Event::Start(start) if start.name().as_ref() == tag_name.as_bytes() => {
+ start
+ }
+ Event::Comment(_) => {
+ continue;
+ }
+ event => {
+ self.leftover_event = Some(event.into_owned());
+ break;
+ }
+ };
+
+ let deserialized = De::deserialize(&start, self).map_err(|err| {
+ DeserializerError::DeserializeFailed(
+ type_name::<De>(),
+ WrappedDeserializeError::new(err),
+ )
+ })?;
+
+ self.read_end_event(tag_name)?;
+
+ deserialized_items.push(deserialized);
+ }
+
+ Ok(deserialized_items)
+ }
+
+ fn de_text(&mut self) -> Result<String, DeserializerError>
+ {
+ let text = match read_event!(self) {
+ Event::Text(text) => Ok(text),
+ event => {
+ self.leftover_event = Some(event.clone().into_owned());
+
+ Err(DeserializerError::UnexpectedEvent {
+ expected_event_name: "text".to_string(),
+ found_event: event,
+ })
+ }
+ }?
+ .unescape()?;
+
+ Ok(text.to_string())
+ }
+
+ fn skip_to_tag_start(&mut self, tag_name: &str) -> Result<(), DeserializerError>
+ {
+ loop {
+ match read_event!(self) {
+ Event::Start(start) if start.name().as_ref() == tag_name.as_bytes() => {
+ self.leftover_event = Some(Event::Start(start).into_owned());
+
+ break;
+ }
+ _ => {}
+ }
+ }
+
+ Ok(())
+ }
+
+ fn skip_to_tag_end(&mut self, tag_name: &str) -> Result<(), DeserializerError>
+ {
+ loop {
+ match read_event!(self) {
+ Event::End(end) if end.name().as_ref() == tag_name.as_bytes() => {
+ self.leftover_event = Some(Event::End(end).into_owned());
+
+ return Ok(());
+ }
+ _ => {}
+ }
+ }
+ }
+}
+
+impl<Source> BufferDeserializer<Source>
+where
+ Source: BufRead,
+{
+ fn read_end_event(&mut self, tag_name: &str) -> Result<(), DeserializerError>
+ {
+ let event = read_event!(self);
+
+ if matches!(&event, Event::End(end) if end.name().as_ref() == tag_name.as_bytes())
+ {
+ return Ok(());
+ }
+
+ Err(DeserializerError::UnexpectedEvent {
+ expected_event_name: "end".to_string(),
+ found_event: event.into_owned(),
+ })
+ }
+}