diff options
Diffstat (limited to 'src/stanza')
-rw-r--r-- | src/stanza/mod.rs | 359 |
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, } |