summaryrefslogtreecommitdiffstats
path: root/src/stanza/mod.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-08-05 20:14:09 +0100
committerLibravatar cel 🌸 <cel@blos.sm>2023-08-05 20:14:09 +0100
commit5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff (patch)
tree4f901d7543fa52e6ec5dac73ab6eef8f6c42e570 /src/stanza/mod.rs
parentdec6f0105d0da5f06f685d49fd4b118975542d07 (diff)
downloadluz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.tar.gz
luz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.tar.bz2
luz-5334cd4ed69d12e4265b8b97ae9e7ed02f78a9ff.zip
WIP: refactor Element type - namespace work
Diffstat (limited to '')
-rw-r--r--src/stanza/mod.rs399
1 files changed, 236 insertions, 163 deletions
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,
}