summaryrefslogtreecommitdiffstats
path: root/src/stanza/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/stanza/mod.rs359
1 files changed, 225 insertions, 134 deletions
diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs
index 8251422..7f4790d 100644
--- a/src/stanza/mod.rs
+++ b/src/stanza/mod.rs
@@ -6,14 +6,15 @@ pub mod sasl;
pub mod stream;
use std::collections::BTreeMap;
+use std::str;
// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None);
use async_recursion::async_recursion;
-use quick_xml::events::{BytesStart, Event};
+use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::{Reader, Writer};
use tokio::io::{AsyncBufRead, AsyncWrite};
-use crate::JabberError;
+use crate::{JabberError, Result};
// #[derive(Clone, Debug)]
// pub struct EventTree<'e> {
@@ -29,6 +30,9 @@ pub struct Element<'s> {
/// element prefix
/// e.g. `foo` in `<foo:bar />`.
prefix: Option<&'s str>,
+ /// element name
+ /// e.g. `bar` in `<foo:bar />`.
+ localname: &'s str,
/// qualifying namespace
/// an element must be qualified by a namespace
/// e.g. for `<stream:features>` in
@@ -57,9 +61,6 @@ pub struct Element<'s> {
/// ```
/// 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
/// ```
@@ -73,12 +74,11 @@ pub struct Element<'s> {
/// ```
/// 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>>,
+ namespace_declarations: 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>>>>,
+ children: Box<Vec<Node<'s>>>,
}
#[derive(Clone, Debug)]
@@ -87,190 +87,281 @@ pub enum Node<'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));
+impl<'s> From<&Node<'s>> for Vec<Event<'s>> {
+ fn from(node: &Node<'s>) -> Self {
+ match node {
+ Node::Element(e) => e.into(),
+ Node::Text(t) => vec![Event::Text(BytesText::new(t))],
+ }
+ }
+}
+
+impl<'s> Element<'s> {
+ /// returns the fully qualified name
+ /// e.g. `foo:bar` in
+ /// `<foo:bar>`.
+ pub fn name(&self) -> &str {
+ if let Some(prefix) = self.prefix {
+ format!("{}:{}", prefix, self.localname).as_str()
} else {
- event = BytesStart::new(element.name);
+ self.localname
}
+ }
- event
-
- let event = event.with_attributes(element.attributes.into_iter());
+ /// returns the localname.
+ /// e.g. `bar` in `<foo:bar>`
+ pub fn localname(&self) -> &str {
+ self.localname
+ }
- match element.children.is_none() {
- true => return Event::Empty(event),
- false => return Event::Start(event),
- }
+ /// returns the prefix.
+ /// e.g. `foo` in `<foo:bar>`. returns None if there is
+ /// no prefix.
+ pub fn prefix(&self) -> Option<&str> {
+ self.prefix
}
-}
-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 {
+ /// `<element xmlns='foo' xmlns:bar='bar'>`
+ /// it will be `foo` but for
+ /// `<bar:element xmlns='foo' xmlns:bar='bar'>`
+ /// it will be `bar`.
+ pub fn namespace(&self) -> &str {
self.namespace
}
}
-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.children.is_empty() {
- true => {}
+impl<'s> From<&Element<'s>> for Vec<Event<'s>> {
+ fn from(element: &Element<'s>) -> Self {
+ let name = element.name();
+
+ let event = BytesStart::new(name);
+
+ // namespace declarations
+ let namespace_declarations = element.namespace_declarations.iter().map(|declaration| {
+ let (prefix, namespace) = declaration;
+ match prefix {
+ Some(prefix) => return (format!("xmlns:{}", prefix).as_str(), *namespace),
+ None => return ("xmlns", *namespace),
}
- 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(());
+ });
+ let event = event.with_attributes(namespace_declarations);
+
+ // attributes
+ let event = event.with_attributes(element.attributes.into_iter());
+
+ match element.children.is_empty() {
+ true => return vec![Event::Empty(event)],
+ false => {
+ return {
+ let start: Vec<Event<'s>> = vec![Event::Start(event)];
+ let start_and_content: Vec<Event<'s>> = start
+ .into_iter()
+ .chain({
+ let u = element.children.iter().fold(
+ Vec::new(),
+ |acc: Vec<Event<'s>>, child: &Node<'s>| {
+ acc.into_iter()
+ .chain(Into::<Vec<Event<'s>>>::into(child).into_iter())
+ .collect()
+ },
+ );
+ u
+ })
+ .collect();
+ let full: Vec<Event<'s>> = start_and_content
+ .into_iter()
+ .chain(vec![Event::End(BytesEnd::new(name))])
+ .collect();
+ full
}
- e => Ok(writer.write_event_async(e).await?),
}
- })
+ }
}
}
-impl<'e> Element<'e> {
+impl<'s> Element<'s> {
+ /// if there is only one child in the vec of children, will return that element
+ pub fn child(&self) -> Result<&Element<'s>> {
+ if self.children.len() == 1 {
+ Ok(&self.children[0])
+ } else {
+ Err(ElementError::NoChildren.into())
+ }
+ }
+
+ /// returns reference to children
+ pub fn children(&self) -> Result<&Vec<Element<'s>>> {
+ if !self.children.is_empty() {
+ Ok(&self.children)
+ } else {
+ Err(ElementError::NoChildren.into())
+ }
+ }
+
+ /// returns text content, error if there is none
+ pub fn content(&self) -> Result<&str> {
+ for node in *self.children {
+ match node {
+ Node::Text(t) => return Ok(t),
+ _ => {}
+ }
+ }
+ Err(ElementError::NotText)
+ }
+
+ pub async fn write<W: AsyncWrite + Unpin + Send>(&self, writer: &mut Writer<W>) -> Result<()> {
+ let events: Vec<Event> = self.into();
+ for event in events {
+ writer.write_event_async(event).await?
+ }
+ Ok(())
+ }
+
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()),
- }
+ ) -> Result<()> {
+ let mut event = BytesStart::new(self.name());
+
+ // namespace declarations
+ self.namespace_declarations.iter().for_each(|declaration| {
+ let (prefix, namespace) = declaration;
+ match prefix {
+ Some(prefix) => {
+ event.push_attribute((format!("xmlns:{}", prefix).as_str(), *namespace))
+ }
+ None => event.push_attribute(("xmlns", *namespace)),
+ }
+ });
+
+ // attributes
+ let event =
+ event.with_attributes(self.attributes.iter().map(|(attr, value)| (*attr, *value)));
+
+ writer.write_event_async(Event::Start(event)).await?;
+
+ Ok(())
}
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()),
- }
+ ) -> Result<()> {
+ let event = BytesEnd::new(self.name());
+ writer.write_event_async(Event::End(event)).await?;
+ Ok(())
}
+ // 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)
+ local_namespaces: BTreeMap<Option<&str>, &str>,
+ ) -> Result<Self> {
+ let node = Node::read_recursive(reader, local_namespaces)
.await?
- .ok_or(JabberError::UnexpectedEnd);
- element
+ .ok_or(JabberError::UnexpectedEnd)?;
+ match node {
+ Node::Element(e) => Ok(e),
+ Node::Text(_) => Err(JabberError::UnexpectedText),
+ }
}
+}
+impl<'s> Node<'s> {
#[async_recursion]
async fn read_recursive<R: AsyncBufRead + Unpin + Send>(
reader: &mut Reader<R>,
- ) -> Result<Option<Self>, JabberError> {
+ local_namespaces: BTreeMap<Option<&str>, &str>,
+ ) -> Result<Option<Node<'s>>> {
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();
+ let prefix = e
+ .name()
+ .prefix()
+ .map(|prefix| str::from_utf8(prefix.into_inner())?);
+
+ let mut children_vec: 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,
- }))
+ Ok(Some(Self::Element(Element {
+ prefix,
+ localname: e.local_name().into_inner(),
+ namespace: todo!(),
+ namespace_declarations: todo!(),
+ attributes: todo!(),
+ children: todo!(),
+ })))
}
Event::End(_) => Ok(None),
+ Event::Text(e) => Ok(Some(Self::Text(e.unescape()?.as_ref()))),
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>(&'p self) -> Result<&'p Element<'e>, ElementError<'static>> {
- if let Some(children) = &self.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>(&'p self) -> Result<&'p Vec<Element<'e>>, ElementError<'e>> {
- if let Some(children) = &self.children {
- return Ok(children);
- }
- Err(ElementError::NoChildren)
- }
}
-pub trait IntoElement<'e> {
- fn event(&self) -> Event<'e>;
- fn children(&self) -> Option<Vec<Element<'e>>>;
-}
+// #[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()),
+// }
+// }
-impl<'e, T: IntoElement<'e>> From<T> for Element<'e> {
- fn from(value: T) -> Self {
- Element {
- event: value.event(),
- children: value.children(),
- }
- }
-}
+// pub trait IntoElement<'e> {
+// fn event(&self) -> Event<'e>;
+// fn children(&self) -> Option<Vec<Element<'e>>>;
+// }
+
+// impl<'e, T: IntoElement<'e>> From<T> for Element<'e> {
+// fn from(value: T) -> Self {
+// Element {
+// event: value.event(),
+// children: value.children(),
+// }
+// }
+// }
#[derive(Debug)]
pub enum ElementError<'e> {
NotAStart(Event<'e>),
+ NotText,
NoChildren,
MultipleChildren,
}