WIP: refactor Element type

This commit is contained in:
cel 🌸 2023-08-05 16:47:52 +01:00
parent 2a7b8834d7
commit 8ab4a8b436
2 changed files with 227 additions and 135 deletions

View File

@ -25,6 +25,7 @@ pub enum JabberError {
ParseError, ParseError,
UnexpectedEnd, UnexpectedEnd,
UnexpectedElement, UnexpectedElement,
UnexpectedText,
XML(quick_xml::Error), XML(quick_xml::Error),
SASL(SASLError), SASL(SASLError),
Element(ElementError<'static>), Element(ElementError<'static>),

View File

@ -6,14 +6,15 @@ pub mod sasl;
pub mod stream; pub mod stream;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str;
// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None); // const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None);
use async_recursion::async_recursion; 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 quick_xml::{Reader, Writer};
use tokio::io::{AsyncBufRead, AsyncWrite}; use tokio::io::{AsyncBufRead, AsyncWrite};
use crate::JabberError; use crate::{JabberError, Result};
// #[derive(Clone, Debug)] // #[derive(Clone, Debug)]
// pub struct EventTree<'e> { // pub struct EventTree<'e> {
@ -29,6 +30,9 @@ pub struct Element<'s> {
/// element prefix /// element prefix
/// e.g. `foo` in `<foo:bar />`. /// e.g. `foo` in `<foo:bar />`.
prefix: Option<&'s str>, prefix: Option<&'s str>,
/// element name
/// e.g. `bar` in `<foo:bar />`.
localname: &'s str,
/// qualifying namespace /// qualifying namespace
/// an element must be qualified by a namespace /// an element must be qualified by a namespace
/// e.g. for `<stream:features>` in /// e.g. for `<stream:features>` in
@ -57,9 +61,6 @@ pub struct Element<'s> {
/// ``` /// ```
/// would be `"jabber:client"` /// would be `"jabber:client"`
namespace: &'s str, namespace: &'s str,
/// element name
/// e.g. `bar` in `<foo:bar />`.
name: &'s str,
/// all namespaces applied to element /// all namespaces applied to element
/// e.g. for `<bind>` in /// e.g. for `<bind>` in
/// ``` /// ```
@ -73,12 +74,11 @@ pub struct Element<'s> {
/// ``` /// ```
/// would be `[(None, "urn:ietf:params:xml:ns:xmpp-bind")]` despite /// would be `[(None, "urn:ietf:params:xml:ns:xmpp-bind")]` despite
/// `(Some("stream"), "http://etherx.jabber.org/streams")` also being available /// `(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 /// element attributes
attributes: Box<BTreeMap<&'s str, &'s str>>, attributes: Box<BTreeMap<&'s str, &'s str>>,
// children elements namespaces contain their parents' namespaces // children elements namespaces contain their parents' namespaces
/// children: Box<Vec<Node<'s>>>,
children: Option<Box<Vec<Node<'s>>>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -87,190 +87,281 @@ pub enum Node<'s> {
Text(&'s str), Text(&'s str),
} }
impl<'s> From<&Element<'s>> for Event<'s> { impl<'s> From<&Node<'s>> for Vec<Event<'s>> {
fn from(element: &Element<'s>) -> Self { fn from(node: &Node<'s>) -> Self {
let event; match node {
if let Some(prefix) = element.prefix { Node::Element(e) => e.into(),
event = BytesStart::new(format!("{}:{}", prefix, element.name)); Node::Text(t) => vec![Event::Text(BytesText::new(t))],
} 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> { 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 {
self.localname
}
}
/// returns the localname.
/// e.g. `bar` in `<foo:bar>`
pub fn localname(&self) -> &str {
self.localname
}
/// returns the prefix.
/// e.g. `foo` in `<foo:bar>`. returns None if there is
/// no prefix.
pub fn prefix(&self) -> Option<&str> {
self.prefix
}
/// returns the namespace which applies to the current element, e.g. for /// returns the namespace which applies to the current element, e.g. for
/// `<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>` /// `<element xmlns='foo' xmlns:bar='bar'>`
/// it will be `http://etherx.jabber.org/streams` but for /// it will be `foo` but for
/// `<stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>` /// `<bar:element xmlns='foo' xmlns:bar='bar'>`
/// it will be `jabber:client`. /// it will be `bar`.
pub fn get_namespace(&self) -> &str { pub fn namespace(&self) -> &str {
self.namespace self.namespace
} }
} }
impl<'e: 'async_recursion, 'async_recursion> Element<'e> { impl<'s> From<&Element<'s>> for Vec<Event<'s>> {
pub fn write<'life0, W: AsyncWrite + Unpin + Send>( fn from(element: &Element<'s>) -> Self {
&'async_recursion self, let name = element.name();
writer: &'life0 mut Writer<W>,
) -> ::core::pin::Pin< let event = BytesStart::new(name);
Box<
dyn ::core::future::Future<Output = Result<(), JabberError>> // namespace declarations
+ 'async_recursion let namespace_declarations = element.namespace_declarations.iter().map(|declaration| {
+ ::core::marker::Send, let (prefix, namespace) = declaration;
>, match prefix {
> Some(prefix) => return (format!("xmlns:{}", prefix).as_str(), *namespace),
where None => return ("xmlns", *namespace),
W: 'async_recursion,
'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?;
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?),
} }
});
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
}
}
}
} }
} }
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>( pub async fn write_start<W: AsyncWrite + Unpin + Send>(
&self, &self,
writer: &mut Writer<W>, writer: &mut Writer<W>,
) -> Result<(), JabberError> { ) -> Result<()> {
match self.event.as_ref() { let mut event = BytesStart::new(self.name());
Event::Start(e) => Ok(writer.write_event_async(Event::Start(e.clone())).await?),
e => Err(ElementError::NotAStart(e.clone().into_owned()).into()), // 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>( pub async fn write_end<W: AsyncWrite + Unpin + Send>(
&self, &self,
writer: &mut Writer<W>, writer: &mut Writer<W>,
) -> Result<(), JabberError> { ) -> Result<()> {
match self.event.as_ref() { let event = BytesEnd::new(self.name());
Event::Start(e) => Ok(writer writer.write_event_async(Event::End(event)).await?;
.write_event_async(Event::End(e.clone().to_end())) Ok(())
.await?),
e => Err(ElementError::NotAStart(e.clone().into_owned()).into()),
}
} }
// 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] #[async_recursion]
pub async fn read<R: AsyncBufRead + Unpin + Send>( pub async fn read<R: AsyncBufRead + Unpin + Send>(
reader: &mut Reader<R>, reader: &mut Reader<R>,
) -> Result<Self, JabberError> { local_namespaces: BTreeMap<Option<&str>, &str>,
let element = Self::read_recursive(reader) ) -> Result<Self> {
let node = Node::read_recursive(reader, local_namespaces)
.await? .await?
.ok_or(JabberError::UnexpectedEnd); .ok_or(JabberError::UnexpectedEnd)?;
element match node {
Node::Element(e) => Ok(e),
Node::Text(_) => Err(JabberError::UnexpectedText),
} }
}
}
impl<'s> Node<'s> {
#[async_recursion] #[async_recursion]
async fn read_recursive<R: AsyncBufRead + Unpin + Send>( async fn read_recursive<R: AsyncBufRead + Unpin + Send>(
reader: &mut Reader<R>, reader: &mut Reader<R>,
) -> Result<Option<Self>, JabberError> { local_namespaces: BTreeMap<Option<&str>, &str>,
) -> Result<Option<Node<'s>>> {
let mut buf = Vec::new(); let mut buf = Vec::new();
let event = reader.read_event_into_async(&mut buf).await?; let event = reader.read_event_into_async(&mut buf).await?;
match event { match event {
Event::Start(e) => { 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? { while let Some(sub_element) = Element::read_recursive(reader).await? {
children_vec.push(sub_element) children_vec.push(sub_element)
} }
let mut children = None; Ok(Some(Self::Element(Element {
if !children_vec.is_empty() { prefix,
children = Some(children_vec) localname: e.local_name().into_inner(),
} namespace: todo!(),
Ok(Some(Self { namespace_declarations: todo!(),
event: Event::Start(e.into_owned()), attributes: todo!(),
children, children: todo!(),
})) })))
} }
Event::End(_) => Ok(None), Event::End(_) => Ok(None),
Event::Text(e) => Ok(Some(Self::Text(e.unescape()?.as_ref()))),
e => Ok(Some(Self { e => Ok(Some(Self {
event: e.into_owned(), event: e.into_owned(),
children: None, 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> { // #[async_recursion]
fn event(&self) -> Event<'e>; // pub async fn read_start<R: AsyncBufRead + Unpin + Send>(
fn children(&self) -> Option<Vec<Element<'e>>>; // 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> { // pub trait IntoElement<'e> {
fn from(value: T) -> Self { // fn event(&self) -> Event<'e>;
Element { // fn children(&self) -> Option<Vec<Element<'e>>>;
event: value.event(), // }
children: value.children(),
} // impl<'e, T: IntoElement<'e>> From<T> for Element<'e> {
} // fn from(value: T) -> Self {
} // Element {
// event: value.event(),
// children: value.children(),
// }
// }
// }
#[derive(Debug)] #[derive(Debug)]
pub enum ElementError<'e> { pub enum ElementError<'e> {
NotAStart(Event<'e>), NotAStart(Event<'e>),
NotText,
NoChildren, NoChildren,
MultipleChildren, MultipleChildren,
} }