diff options
author | cel 🌸 <cel@blos.sm> | 2023-08-05 20:14:09 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-08-05 20:14:09 +0100 |
commit | 5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff (patch) | |
tree | 4f901d7543fa52e6ec5dac73ab6eef8f6c42e570 /src | |
parent | dec6f0105d0da5f06f685d49fd4b118975542d07 (diff) | |
download | luz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.tar.gz luz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.tar.bz2 luz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.zip |
WIP: refactor Element type - namespace work
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 9 | ||||
-rw-r--r-- | src/stanza/bind.rs | 29 | ||||
-rw-r--r-- | src/stanza/mod.rs | 399 |
3 files changed, 271 insertions, 166 deletions
diff --git a/src/error.rs b/src/error.rs index 8aa98ae..9278f1b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use rsasl::mechname::MechanismNameError; use crate::{ jid::ParseError, - stanza::{self, ElementError}, + stanza::{self, ElementError, ElementParseError}, }; #[derive(Debug)] @@ -22,6 +22,7 @@ pub enum JabberError { NoType, IDMismatch, BindError, + ElementParse(ElementParseError), ParseError, UnexpectedEnd, UnexpectedElement, @@ -87,3 +88,9 @@ impl From<ParseError> for JabberError { Self::JID(e) } } + +impl From<ElementParseError> for JabberError { + fn from(e: ElementParseError) -> Self { + Self::ElementParse(e) + } +} diff --git a/src/stanza/bind.rs b/src/stanza/bind.rs index f1bdc2d..5e9704f 100644 --- a/src/stanza/bind.rs +++ b/src/stanza/bind.rs @@ -1,10 +1,12 @@ +use std::collections::BTreeMap; + use quick_xml::{ events::{BytesStart, BytesText, Event}, name::QName, Reader, }; -use super::{Element, IntoElement}; +use super::{Element, IntoElement, Node}; use crate::{JabberError, JID}; const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind"; @@ -14,7 +16,30 @@ pub struct Bind { pub jid: Option<JID>, } -impl<'e> IntoElement<'e> for Bind { +impl From<Bind> for Element { + fn from(value: Bind) -> Self { + let mut namespace_declarations = Box::new(BTreeMap::new()); + namespace_declarations.insert(None, XMLNS.to_owned()); + let mut children = Vec::new(); + if let Some(resource) = value.resource { + children.push(Node::Element( + Element { prefix: None, localname: "", namespace: , namespace_declarations: , attributes: , children: } + ) + + ) + } + Self { + prefix: None, + localname: "bind".to_string(), + namespace: XMLNS.to_owned(), + namespace_declarations, + attributes: todo!(), + children: todo!(), + } + } +} + +impl IntoElement for Bind { fn event(&self) -> quick_xml::events::Event<'static> { let mut bind_event = BytesStart::new("bind"); bind_event.push_attribute(("xmlns", XMLNS)); diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index e96ae9c..1bb3fc2 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -17,23 +17,17 @@ use tokio::io::{AsyncBufRead, AsyncWrite}; use crate::{JabberError, Result}; -// #[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)] /// represents an xml element as a tree of nodes -pub struct Element<'s> { +pub struct Element { /// element prefix /// e.g. `foo` in `<foo:bar />`. - prefix: Option<&'s str>, + prefix: Option<String>, /// element name /// e.g. `bar` in `<foo:bar />`. - localname: &'s str, + localname: String, /// qualifying namespace /// an element must be qualified by a namespace /// e.g. for `<stream:features>` in @@ -61,7 +55,7 @@ pub struct Element<'s> { /// </stream:stream> /// ``` /// would be `"jabber:client"` - namespace: &'s str, + namespace: String, /// all namespaces applied to element /// e.g. for `<bind>` in /// ``` @@ -75,22 +69,49 @@ 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 - namespace_declarations: Box<BTreeMap<Option<&'s str>, &'s str>>, + // TODO: maybe not even needed, as can calculate when writing which namespaces need to be declared + // but then can't have unused namespace on element, confusing. + namespace_declarations: Box<BTreeMap<Option<String>, String>>, /// element attributes - attributes: Box<BTreeMap<&'s str, &'s str>>, + attributes: Box<BTreeMap<String, String>>, // children elements namespaces contain their parents' namespaces - children: Box<Vec<Node<'s>>>, + children: Box<Vec<Node>>, +} + +impl Element { + pub fn new_empty<S: ToString, C: Into<Node>>( + prefix: Option<S>, + localname: S, + namespace: S, + namespace_declarations: BTreeMap<Option<S>, S>, + attributes: BTreeMap<S, S>, + children: Vec<C>, + ) { + } + pub fn push_child<C: Into<Node>>(&mut self, node: C) {} } #[derive(Clone, Debug)] -pub enum Node<'s> { - Element(Element<'s>), - Text(&'s str), +pub enum Node { + Element(Element), + Text(String), Unknown, } -impl<'s> From<&Node<'s>> for Vec<Event<'s>> { - fn from(node: &Node<'s>) -> Self { +impl From<Element> for Node { + fn from(element: Element) -> Self { + Self::Element(element) + } +} + +impl<S: ToString> From<S> for Node { + fn from(text: S) -> Self { + Self::Text(text.to_string()) + } +} + +impl<'s> From<&Node> for Vec<Event<'s>> { + fn from(node: &Node) -> Self { match node { Node::Element(e) => e.into(), Node::Text(t) => vec![Event::Text(BytesText::new(t))], @@ -99,7 +120,7 @@ impl<'s> From<&Node<'s>> for Vec<Event<'s>> { } } -impl<'s> Element<'s> { +impl Element { /// returns the fully qualified name /// e.g. `foo:bar` in /// `<foo:bar>`. @@ -107,14 +128,14 @@ impl<'s> Element<'s> { if let Some(prefix) = self.prefix { format!("{}:{}", prefix, self.localname).as_str() } else { - self.localname + &self.localname } } /// returns the localname. /// e.g. `bar` in `<foo:bar>` pub fn localname(&self) -> &str { - self.localname + &self.localname } /// returns the prefix. @@ -130,12 +151,12 @@ impl<'s> Element<'s> { /// `<bar:element xmlns='foo' xmlns:bar='bar'>` /// it will be `bar`. pub fn namespace(&self) -> &str { - self.namespace + &self.namespace } } -impl<'s> From<&Element<'s>> for Vec<Event<'s>> { - fn from(element: &Element<'s>) -> Self { +impl<'s> From<&Element> for Vec<Event<'s>> { + fn from(element: &Element) -> Self { let name = element.name(); let event = BytesStart::new(name); @@ -183,9 +204,9 @@ impl<'s> From<&Element<'s>> for Vec<Event<'s>> { } } -impl<'s> Element<'s> { +impl Element { /// if there is only one child in the vec of children, will return that element - pub fn child(&self) -> Result<&Node<'s>> { + pub fn child(&self) -> Result<&Node> { if self.children.len() == 1 { Ok(&self.children[0]) } else if self.children.len() > 1 { @@ -196,7 +217,7 @@ impl<'s> Element<'s> { } /// returns reference to children - pub fn children(&self) -> Result<&Vec<Node<'s>>> { + pub fn children(&self) -> Result<&Vec<Node>> { if !self.children.is_empty() { Ok(&self.children) } else { @@ -206,7 +227,7 @@ impl<'s> Element<'s> { /// returns text content, error if there is none pub fn text_content(&self) -> Result<Vec<&str>> { - let text = Vec::new(); + let mut text = Vec::new(); for node in *self.children { match node { Node::Text(t) => text.push(t), @@ -214,43 +235,86 @@ impl<'s> Element<'s> { } } if text.is_empty() { - Err(ElementError::NotText) + return Err(ElementError::NotText.into()); } Ok(text) } - 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? + /// returns whether or not the element is qualified by a namespace, either declared + /// by a parent, or itself. + fn namespace_qualified<S: AsRef<str>>( + &self, + local_namespaces: &BTreeMap<Option<S>, S>, + ) -> bool { + if let Some(namespace) = local_namespaces.get(self.prefix) { + if namespace != self.namespace { + return false; + } + }; + + if let Some(namespace) = self.namespace_declarations.get(&self.prefix) { + if namespace != self.namespace { + return false; + } + } + + for child in *self.children { + if child.namespace_qualified(local_namespaces) == false { + return false; + } } - Ok(()) + + true } - pub async fn write_start<W: AsyncWrite + Unpin + Send>( + /// writes an element to a writer. the element's namespace must be qualified by the + /// context given in `local_namespaces` or the element's internal namespace declarations + pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>( &self, writer: &mut Writer<W>, + local_namespaces: &BTreeMap<Option<S>, S>, ) -> Result<()> { - let mut event = BytesStart::new(self.name()); + // TODO: NEXT: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s + if self.namespace_qualified(local_namespaces) { + let events: Vec<Event> = self.into(); + for event in events { + writer.write_event_async(event).await? + } + Ok(()) + } else { + Err(ElementError::NamespaceNotQualified.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)) + pub async fn write_start<S: AsRef<str>, W: AsyncWrite + Unpin + Send>( + &self, + writer: &mut Writer<W>, + local_namespaces: &BTreeMap<Option<S>, S>, + ) -> Result<()> { + if self.namespace_qualified(local_namespaces) { + 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)), } - None => event.push_attribute(("xmlns", *namespace)), - } - }); + }); - // attributes - let event = - event.with_attributes(self.attributes.iter().map(|(attr, value)| (*attr, *value))); + // attributes + let event = + event.with_attributes(self.attributes.iter().map(|(attr, value)| (*attr, *value))); - writer.write_event_async(Event::Start(event)).await?; + writer.write_event_async(Event::Start(event)).await?; - Ok(()) + Ok(()) + } else { + Err(ElementError::NamespaceNotQualified.into()) + } } pub async fn write_end<W: AsyncWrite + Unpin + Send>( @@ -263,9 +327,9 @@ impl<'s> Element<'s> { } #[async_recursion] - pub async fn read<R: AsyncBufRead + Unpin + Send>( + pub async fn read<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<&str>, &str>, + local_namespaces: &BTreeMap<Option<S>, S>, ) -> Result<Self> { let node = Node::read_recursive(reader, local_namespaces) .await? @@ -276,21 +340,25 @@ impl<'s> Element<'s> { Node::Unknown => Err(JabberError::UnexpectedElement), } } - pub async fn read_start<R: AsyncBufRead + Unpin + Send>( + + pub async fn read_start<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<&str>, &str>, - ) -> Result<Self> { - let mut buf = Vec::new(); + local_namespaces: &BTreeMap<Option<S>, S>, + ) -> Result<Element> { + let buf = Vec::new(); let event = reader.read_event_into_async(&mut buf).await?; match event { Event::Start(e) => { - let prefix = e - .name() - .prefix() - .map(|prefix| str::from_utf8(prefix.into_inner())?); - let localname = str::from_utf8(e.local_name().into_inner())?; + let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); + let converted_prefix; + if let Some(raw_prefix) = prefix { + converted_prefix = Some(str::from_utf8(raw_prefix)?) + } + let prefix = converted_prefix; + + let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - let mut namespaces = local_namespaces.clone(); + let mut local_namespaces = local_namespaces.clone(); let mut namespace_declarations = BTreeMap::new(); let attributes = BTreeMap::new(); @@ -300,62 +368,70 @@ impl<'s> Element<'s> { match prefix_declaration { PrefixDeclaration::Default => { let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations.try_insert(None, value); - namespaces.insert(None, value); + if let Some(_) = namespace_declarations.insert(None, value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(None, value); } PrefixDeclaration::Named(prefix) => { let key = str::from_utf8(prefix)?; let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations - .try_insert(Some(key), value) - .map_err(ParseError::DuplicateAttribute)?; - namespaces.insert(Some(key), value); + if let Some(_) = namespace_declarations.insert(Some(key), value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(Some(key), value); } } } else { - attributes - .try_insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) - .map_err(ParseError::DuplicateAttribute)?; + if let Some(_) = attributes.insert( + str::from_utf8(attribute.key.into_inner())?, + str::from_utf8(attribute.value.as_ref())?, + ) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; } } - let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?; + let namespace = *local_namespaces + .get(&prefix) + .ok_or(ElementParseError::NoNamespace)?; let mut children = Vec::new(); - Ok(Some(Self::Element(Element { + Ok(Self { prefix, localname, namespace, - namespace_declarations, - attributes, - children, - }))) + namespace_declarations: Box::new(namespace_declarations), + attributes: Box::new(attributes), + children: Box::new(children), + }) } - e => Err(ElementError::NotAStart(e)), + e => Err(ElementError::NotAStart(e).into()), } } } -impl<'s> Node<'s> { - async fn read_recursive<R: AsyncBufRead + Unpin + Send>( +impl Node { + #[async_recursion] + async fn read_recursive<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<&str>, &str>, - ) -> Result<Option<Node<'s>>> { + local_namespaces: &BTreeMap<Option<S>, S>, + ) -> Result<Option<Node>> { let mut buf = Vec::new(); let event = reader.read_event_into_async(&mut buf).await?; match event { Event::Empty(e) => { - let prefix = e - .name() - .prefix() - .map(|prefix| str::from_utf8(prefix.into_inner())?); - let localname = str::from_utf8(e.local_name().into_inner())?; + let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); + let converted_prefix; + if let Some(raw_prefix) = prefix { + converted_prefix = Some(str::from_utf8(raw_prefix)?) + } + let prefix = converted_prefix; + + let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - let mut namespaces = local_namespaces.clone(); + let mut local_namespaces = local_namespaces.clone(); let mut namespace_declarations = BTreeMap::new(); let attributes = BTreeMap::new(); @@ -365,49 +441,56 @@ impl<'s> Node<'s> { match prefix_declaration { PrefixDeclaration::Default => { let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations.try_insert(None, value); - namespaces.insert(None, value); + if let Some(_) = namespace_declarations.insert(None, value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(None, value); } PrefixDeclaration::Named(prefix) => { let key = str::from_utf8(prefix)?; let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations - .try_insert(Some(key), value) - .map_err(ParseError::DuplicateAttribute)?; - namespaces.insert(Some(key), value); + if let Some(_) = namespace_declarations.insert(Some(key), value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(Some(key), value); } } } else { - attributes - .try_insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) - .map_err(ParseError::DuplicateAttribute)?; + if let Some(_) = attributes.insert( + str::from_utf8(attribute.key.into_inner())?, + str::from_utf8(attribute.value.as_ref())?, + ) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; } } - let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?; + let namespace = *local_namespaces + .get(&prefix) + .ok_or(ElementParseError::NoNamespace)?; - let children = Vec::new(); + let mut children = Vec::new(); Ok(Some(Self::Element(Element { prefix, localname, namespace, - namespace_declarations, - attributes, - children, + namespace_declarations: Box::new(namespace_declarations), + attributes: Box::new(attributes), + children: Box::new(children), }))) } Event::Start(e) => { - let prefix = e - .name() - .prefix() - .map(|prefix| str::from_utf8(prefix.into_inner())?); - let localname = str::from_utf8(e.local_name().into_inner())?; + let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); + let converted_prefix; + if let Some(raw_prefix) = prefix { + converted_prefix = Some(str::from_utf8(raw_prefix)?) + } + let prefix = converted_prefix; + + let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - let mut namespaces = local_namespaces.clone(); + let mut local_namespaces = local_namespaces.clone(); let mut namespace_declarations = BTreeMap::new(); let attributes = BTreeMap::new(); @@ -417,92 +500,82 @@ impl<'s> Node<'s> { match prefix_declaration { PrefixDeclaration::Default => { let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations.try_insert(None, value); - namespaces.insert(None, value); + if let Some(_) = namespace_declarations.insert(None, value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(None, value); } PrefixDeclaration::Named(prefix) => { let key = str::from_utf8(prefix)?; let value = str::from_utf8(attribute.value.as_ref())?; - namespace_declarations - .try_insert(Some(key), value) - .map_err(ParseError::DuplicateAttribute)?; - namespaces.insert(Some(key), value); + if let Some(_) = namespace_declarations.insert(Some(key), value) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; + local_namespaces.insert(Some(key), value); } } } else { - attributes - .try_insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) - .map_err(ParseError::DuplicateAttribute)?; + if let Some(_) = attributes.insert( + str::from_utf8(attribute.key.into_inner())?, + str::from_utf8(attribute.value.as_ref())?, + ) { + return Err(ElementParseError::DuplicateAttribute.into()); + }; } } - let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?; + let namespace = *local_namespaces + .get(&prefix) + .ok_or(ElementParseError::NoNamespace)?; let mut children = Vec::new(); - while let Some(child_node) = Node::read_recursive(reader, &namespaces).await? { + while let Some(child_node) = Node::read_recursive(reader, &local_namespaces).await? + { children.push(child_node) } + let mut children = Vec::new(); + Ok(Some(Self::Element(Element { prefix, localname, namespace, - namespace_declarations, - attributes, - children, + namespace_declarations: Box::new(namespace_declarations), + attributes: Box::new(attributes), + children: Box::new(children), }))) } Event::End(_) => Ok(None), - Event::Text(e) => Ok(Some(Self::Text(e.unescape()?.as_ref()))), + Event::Text(e) => Ok(Some(Self::Text(e.unescape()?.as_ref().to_string()))), e => Ok(Some(Self::Unknown)), } } + + fn namespace_qualified<S: AsRef<str>>( + &self, + local_namespaces: &BTreeMap<Option<S>, S>, + ) -> bool { + match self { + Self::Element(e) => e.namespace_qualified(local_namespaces), + _ => true, + } + } } -// #[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()), -// } -// } - -// 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(), -// } -// } -// } +// the issue is i don't know how to validate that an element always has a namespace when it is being written +// TODO: ElementBuilder that makes it easier to build an element under a namespace #[derive(Debug)] pub enum ElementError<'e> { NotAStart(Event<'e>), NotText, NoChildren, + NamespaceNotQualified, MultipleChildren, } #[derive(Debug)] -pub enum ParseError { +pub enum ElementParseError { DuplicateAttribute, NoNamespace, } |