summaryrefslogblamecommitdiffstats
path: root/src/element.rs
blob: 21b1a3e52e61b8bd5fc4670d3098341e42eeb82f (plain) (tree)











































































































                                                                                            
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<Vec<Element<'e>>>,
}

// TODO: make method
#[async_recursion]
pub async fn write<'e: 'async_recursion, W: AsyncWrite + Unpin + Send>(
    element: Element<'e>,
    writer: &mut Writer<W>,
) -> 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<W: AsyncWrite + Unpin + Send>(
        &self,
        writer: &mut Writer<W>,
    ) -> 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<W: AsyncWrite + Unpin + Send>(
        &self,
        writer: &mut Writer<W>,
    ) -> 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<R: AsyncBufRead + Unpin + Send>(
        reader: &mut Reader<R>,
    ) -> Result<Option<Self>> {
        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<R: AsyncBufRead + Unpin + Send>(
        reader: &mut Reader<R>,
    ) -> Result<Self> {
        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>),
}