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 { reader: Reader, leftover_event: Option>, buf: Vec, } impl BufferDeserializer 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 Deserializer for BufferDeserializer where Source: BufRead, { fn de_tag( &mut self, tag_name: &str, ignore_end: IgnoreEnd, ) -> Result { self.de_tag_with(tag_name, ignore_end, De::deserialize) } fn de_tag_with( &mut self, tag_name: &str, ignore_end: IgnoreEnd, deserialize: DeserializeFn, ) -> Result where Err: Error + Send + Sync + 'static, DeserializeFn: FnOnce(&BytesStart, &mut Self) -> Result, { 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::(), 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( &mut self, tag_name: &str, ) -> Result, 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::(), WrappedDeserializeError::new(err), ) })?; self.read_end_event(tag_name)?; deserialized_items.push(deserialized); } Ok(deserialized_items) } fn de_text(&mut self) -> Result { 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 BufferDeserializer 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(), }) } }