summaryrefslogtreecommitdiffstats
path: root/src/stanza/mod.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-08-02 18:21:57 +0100
committerLibravatar cel 🌸 <cel@blos.sm>2023-08-02 18:21:57 +0100
commit2a7b8834d750a312eef34ad50d56d49bc9a9341e (patch)
treeec53a008b9bf2a4d88e94250cfd375d4657487ea /src/stanza/mod.rs
parentcd7bb95c0a31d187bfe25bad15043f0b33b111cf (diff)
downloadluz-2a7b8834d750a312eef34ad50d56d49bc9a9341e.tar.gz
luz-2a7b8834d750a312eef34ad50d56d49bc9a9341e.tar.bz2
luz-2a7b8834d750a312eef34ad50d56d49bc9a9341e.zip
WIP: refactor Element type
Diffstat (limited to 'src/stanza/mod.rs')
-rw-r--r--src/stanza/mod.rs110
1 files changed, 106 insertions, 4 deletions
diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs
index ad9e228..8251422 100644
--- a/src/stanza/mod.rs
+++ b/src/stanza/mod.rs
@@ -5,18 +5,117 @@ pub mod iq;
pub mod sasl;
pub mod stream;
+use std::collections::BTreeMap;
+
// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None);
use async_recursion::async_recursion;
-use quick_xml::events::Event;
+use quick_xml::events::{BytesStart, Event};
use quick_xml::{Reader, Writer};
use tokio::io::{AsyncBufRead, AsyncWrite};
use crate::JabberError;
+// #[derive(Clone, Debug)]
+// pub struct EventTree<'e> {
+// pub event: Event<'e>,
+// pub children: Option<Vec<Element<'e>>>,
+// }
+
+pub type Prefix<'s> = Option<&'s str>;
+
#[derive(Clone, Debug)]
-pub struct Element<'e> {
- pub event: Event<'e>,
- pub children: Option<Vec<Element<'e>>>,
+/// represents an xml element as a tree of nodes
+pub struct Element<'s> {
+ /// element prefix
+ /// e.g. `foo` in `<foo:bar />`.
+ prefix: Option<&'s str>,
+ /// qualifying namespace
+ /// an element must be qualified by a namespace
+ /// e.g. for `<stream:features>` in
+ /// ```
+ /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
+ /// <stream:features>
+ /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
+ /// <compression xmlns='http://jabber.org/features/compress'>
+ /// <method>zlib</method>
+ /// <method>lzw</method>
+ /// </compression>
+ /// </stream:features>
+ /// </stream:stream>
+ /// ```
+ /// would be `"http://etherx.jabber.org/streams"` but for
+ /// ```
+ /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
+ /// <features>
+ /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
+ /// <compression xmlns='http://jabber.org/features/compress'>
+ /// <method>zlib</method>
+ /// <method>lzw</method>
+ /// </compression>
+ /// </features>
+ /// </stream:stream>
+ /// ```
+ /// would be `"jabber:client"`
+ namespace: &'s str,
+ /// element name
+ /// e.g. `bar` in `<foo:bar />`.
+ name: &'s str,
+ /// all namespaces applied to element
+ /// e.g. for `<bind>` in
+ /// ```
+ /// <stream:features xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
+ /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
+ /// <compression xmlns='http://jabber.org/features/compress'>
+ /// <method>zlib</method>
+ /// <method>lzw</method>
+ /// </compression>
+ /// </stream:features>
+ /// ```
+ /// would be `[(None, "urn:ietf:params:xml:ns:xmpp-bind")]` despite
+ /// `(Some("stream"), "http://etherx.jabber.org/streams")` also being available
+ namespaces: Box<BTreeMap<Option<&'s str>, &'s str>>,
+ /// element attributes
+ attributes: Box<BTreeMap<&'s str, &'s str>>,
+ // children elements namespaces contain their parents' namespaces
+ ///
+ children: Option<Box<Vec<Node<'s>>>>,
+}
+
+#[derive(Clone, Debug)]
+pub enum Node<'s> {
+ Element(Element<'s>),
+ Text(&'s str),
+}
+
+impl<'s> From<&Element<'s>> for Event<'s> {
+ fn from(element: &Element<'s>) -> Self {
+ let event;
+ if let Some(prefix) = element.prefix {
+ event = BytesStart::new(format!("{}:{}", prefix, element.name));
+ } else {
+ event = BytesStart::new(element.name);
+ }
+
+ event
+
+ let event = event.with_attributes(element.attributes.into_iter());
+
+ match element.children.is_none() {
+ true => return Event::Empty(event),
+ false => return Event::Start(event),
+ }
+ }
+}
+
+impl<'s> Element<'s> {
+ /// returns the namespace which applies to the current element, e.g. for
+ /// `<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>`
+ /// it will be `http://etherx.jabber.org/streams` but for
+ /// `<stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>`
+ /// it will be `jabber:client`.
+ pub fn get_namespace(&self) -> &str {
+ self.namespace
+ }
}
impl<'e: 'async_recursion, 'async_recursion> Element<'e> {
@@ -35,6 +134,9 @@ impl<'e: 'async_recursion, 'async_recursion> Element<'e> {
'life0: 'async_recursion,
{
Box::pin(async move {
+ match &self.children.is_empty() {
+ true => {}
+ }
match &self.event {
Event::Start(e) => {
writer.write_event_async(Event::Start(e.clone())).await?;