//! Buffered XML deserializer. use std::convert::Infallible; use std::io::BufRead; use quick_xml::events::Event; use quick_xml::Reader; use crate::deserializer::{Deserializer, Error, IgnoreEnd, MaybeStatic}; use crate::event::EventExt; use crate::tagged::TagStart; use crate::util::trait_alias; use crate::DeserializeTagged; trait_alias! { /// A XML deserializer source with an internal buffer. pub Source: BufRead + MaybeStatic; } /// XML deserializer using a source which has an internal buffer. pub struct Buffered { reader: Reader, leftover_event: Option>, buf: Vec, } impl Buffered { /// Returns a new [`Buffered`]. pub fn new(source: TSource) -> 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 Buffered { 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: std::error::Error + Send + Sync + 'static, DeserializeFn: FnOnce(&TagStart, &mut Self) -> Result, { let deserialized = match self.read_event()? { Event::Start(start) if start.name().as_ref() == tag_name.as_bytes() => { deserialize(&TagStart::from_inner(start), self) .map_err(Error::DeserializeFailed)? } event => { self.leftover_event = Some(event.clone().into_owned()); return Err(Error::UnexpectedEvent { expected_event_name: format!("start({tag_name})"), found_event: event.describe().unwrap(), }); } }; if let IgnoreEnd::No = ignore_end { self.read_end_event(tag_name.as_bytes()) .map_err(Error::into_with_de_error)?; } Ok(deserialized) } fn de_tag_list>( &mut self, tag_name: Option, ) -> Result, Error> { let mut deserialized_items = Vec::new(); loop { let start = match self.read_event()? { Event::Start(start) if tag_name.as_ref().map_or_else( || true, |expected_tag_name| { start.name().as_ref() == expected_tag_name.as_ref().as_bytes() }, ) => { TagStart::from_inner(start) } Event::Comment(_) => { continue; } event => { self.leftover_event = Some(event.into_owned()); break; } }; let deserialized = De::deserialize(&start, self).map_err(Error::DeserializeFailed)?; self.read_end_event(start.name()) .map_err(Error::into_with_de_error)?; deserialized_items.push(deserialized); } Ok(deserialized_items) } fn de_text(&mut self) -> Result> { let text = match self.read_event::()? { Event::Text(text) => Ok(text), event => { self.leftover_event = Some(event.clone().into_owned()); Err(Error::::UnexpectedEvent { expected_event_name: "text".to_string(), found_event: event.describe().unwrap(), }) } }? .unescape() .map_err(|err| Error::::XMLError(err.into()))?; Ok(text.to_string()) } fn skip_to_tag_start(&mut self, tag_name: &str) -> Result<(), Error> { loop { match self.read_event::()? { 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<(), Error> { loop { match self.read_event::()? { Event::End(end) if end.name().as_ref() == tag_name.as_bytes() => { self.leftover_event = Some(Event::End(end).into_owned()); return Ok(()); } _ => {} } } } } impl Buffered { fn read_end_event(&mut self, tag_name: &[u8]) -> Result<(), Error> { let event = self.read_event::()?; if matches!(&event, Event::End(end) if end.name().as_ref() == tag_name) { return Ok(()); } Err(Error::UnexpectedEvent { expected_event_name: "end".to_string(), found_event: event.describe().unwrap(), }) } fn read_event(&mut self) -> Result, Error> { let event = if let Some(leftover_event) = self.leftover_event.take() { leftover_event } else { self.reader .read_event_into(&mut self.buf) .map_err(|err| Error::::XMLError(err.into()))? .into_owned() }; if let Event::Eof = &event { return Err(Error::UnexpectedEndOfFile); } Ok(event) } }