summaryrefslogtreecommitdiffstats
path: root/src/stanza/mod.rs
blob: 16f3bdd270738a446f15d096a2a450e3826c2bef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 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::Result;

#[derive(Debug)]
pub struct Element<'e> {
    pub event: Event<'e>,
    pub content: 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<()>>
                + '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(content) = &self.content {
                        for _e in content {
                            self.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<()> {
        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>),
}