use async_recursion::async_recursion; use quick_xml::events::Event; use quick_xml::{Reader, Writer}; use tokio::io::{AsyncBufRead, AsyncWrite}; use crate::Result; #[derive(Debug)] pub struct Element<'e> { pub event: Event<'e>, pub content: Option>>, } // TODO: make method #[async_recursion] pub async fn write<'e: 'async_recursion, W: AsyncWrite + Unpin + Send>( element: Element<'e>, writer: &mut Writer, ) -> Result<()> { match element.event { Event::Start(e) => { writer.write_event_async(Event::Start(e.clone())).await?; if let Some(content) = element.content { for e in content { write(e, writer).await?; } } writer.write_event_async(Event::End(e.to_end())).await?; return Ok(()); } e => Ok(writer.write_event_async(e).await?), } } impl<'e> Element<'e> { pub async fn write_start( &self, writer: &mut Writer, ) -> Result<()> { match self.event.as_ref() { Event::Start(e) => Ok(writer.write_event_async(Event::Start(e.clone())).await?), e => Err(ElementError::NotAStart(e.clone().into_owned()).into()), } } pub async fn write_end( &self, writer: &mut Writer, ) -> Result<()> { match self.event.as_ref() { Event::Start(e) => Ok(writer .write_event_async(Event::End(e.clone().to_end())) .await?), e => Err(ElementError::NotAStart(e.clone().into_owned()).into()), } } #[async_recursion] pub async fn read( reader: &mut Reader, ) -> Result> { let mut buf = Vec::new(); let event = reader.read_event_into_async(&mut buf).await?; match event { Event::Start(e) => { let mut content_vec = Vec::new(); while let Some(sub_element) = Element::read(reader).await? { content_vec.push(sub_element) } let mut content = None; if !content_vec.is_empty() { content = Some(content_vec) } Ok(Some(Self { event: Event::Start(e.into_owned()), content, })) } Event::End(_) => Ok(None), e => Ok(Some(Self { event: e.into_owned(), content: None, })), } } #[async_recursion] pub async fn read_start( reader: &mut Reader, ) -> Result { let mut buf = Vec::new(); let event = reader.read_event_into_async(&mut buf).await?; match event { Event::Start(e) => { return Ok(Self { event: Event::Start(e.into_owned()), content: None, }) } e => Err(ElementError::NotAStart(e.into_owned()).into()), } } } #[derive(Debug)] pub enum ElementError<'e> { NotAStart(Event<'e>), }