aboutsummaryrefslogblamecommitdiffstats
path: root/src/stanza/mod.rs
blob: c29b1a20aa7bae618ac854beaca4c28c61304c70 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11

                                    
             
               

                                                                        




                                          
                       
 
                       

                         
                                           







                                                          
                                                                        











                                                                             


                                                            














                                                                            
                                  








                                                                                            
                                  










                                                                             










                                                            



                                                                  


                                                                                      
                 


                                                 


                                                        
                             




                                      
                               






                                                            
                                    





                                                                  
                                   






                                                                     





















                                                                                                  


                           

                     
 
// use quick_xml::events::BytesDecl;

pub mod sasl;
pub mod stream;

// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None);
use async_recursion::async_recursion;
use quick_xml::events::Event;
use quick_xml::{Reader, Writer};
use tokio::io::{AsyncBufRead, AsyncWrite};

use crate::JabberError;

#[derive(Clone, Debug)]
pub struct Element<'e> {
    pub event: Event<'e>,
    pub children: Option<Vec<Element<'e>>>,
}

impl<'e: 'async_recursion, 'async_recursion> Element<'e> {
    pub fn write<'life0, W: AsyncWrite + Unpin + Send>(
        &'async_recursion self,
        writer: &'life0 mut Writer<W>,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<(), JabberError>>
                + 'async_recursion
                + ::core::marker::Send,
        >,
    >
    where
        W: 'async_recursion,
        'life0: 'async_recursion,
    {
        Box::pin(async move {
            match &self.event {
                Event::Start(e) => {
                    writer.write_event_async(Event::Start(e.clone())).await?;
                    if let Some(children) = &self.children {
                        for e in children {
                            e.write(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<(), JabberError> {
        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<(), JabberError> {
        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<Self, JabberError> {
        let element = Self::read_recursive(reader)
            .await?
            .ok_or(JabberError::UnexpectedEnd);
        element
    }

    #[async_recursion]
    async fn read_recursive<R: AsyncBufRead + Unpin + Send>(
        reader: &mut Reader<R>,
    ) -> Result<Option<Self>, JabberError> {
        let mut buf = Vec::new();
        let event = reader.read_event_into_async(&mut buf).await?;
        match event {
            Event::Start(e) => {
                let mut children_vec = Vec::new();
                while let Some(sub_element) = Element::read_recursive(reader).await? {
                    children_vec.push(sub_element)
                }
                let mut children = None;
                if !children_vec.is_empty() {
                    children = Some(children_vec)
                }
                Ok(Some(Self {
                    event: Event::Start(e.into_owned()),
                    children,
                }))
            }
            Event::End(_) => Ok(None),
            e => Ok(Some(Self {
                event: e.into_owned(),
                children: None,
            })),
        }
    }

    #[async_recursion]
    pub async fn read_start<R: AsyncBufRead + Unpin + Send>(
        reader: &mut Reader<R>,
    ) -> Result<Self, JabberError> {
        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()),
                    children: None,
                })
            }
            e => Err(ElementError::NotAStart(e.into_owned()).into()),
        }
    }
}

/// if there is only one child in the vec of children, will return that element
pub fn child<'p, 'e>(element: &'p Element<'e>) -> Result<&'p Element<'e>, ElementError<'static>> {
    if let Some(children) = &element.children {
        if children.len() == 1 {
            return Ok(&children[0]);
        } else {
            return Err(ElementError::MultipleChildren);
        }
    }
    Err(ElementError::NoChildren)
}

/// returns reference to children
pub fn children<'p, 'e>(
    element: &'p Element<'e>,
) -> Result<&'p Vec<Element<'e>>, ElementError<'e>> {
    if let Some(children) = &element.children {
        return Ok(children);
    }
    Err(ElementError::NoChildren)
}

#[derive(Debug)]
pub enum ElementError<'e> {
    NotAStart(Event<'e>),
    NoChildren,
    MultipleChildren,
}