From 2536fa4937f0283b4187142cc6cede8e1dbfafa8 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Fri, 20 Oct 2023 02:34:47 +0100 Subject: WIP: mess --- src/stanza/mod.rs | 132 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 28 deletions(-) (limited to 'src/stanza/mod.rs') diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index 1bb3fc2..13fc31e 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -17,8 +17,6 @@ use tokio::io::{AsyncBufRead, AsyncWrite}; use crate::{JabberError, Result}; -pub type Prefix<'s> = Option<&'s str>; - #[derive(Clone, Debug)] /// represents an xml element as a tree of nodes pub struct Element { @@ -78,19 +76,6 @@ pub struct Element { children: Box>, } -impl Element { - pub fn new_empty>( - prefix: Option, - localname: S, - namespace: S, - namespace_declarations: BTreeMap, S>, - attributes: BTreeMap, - children: Vec, - ) { - } - pub fn push_child>(&mut self, node: C) {} -} - #[derive(Clone, Debug)] pub enum Node { Element(Element), @@ -244,22 +229,22 @@ impl Element { /// by a parent, or itself. fn namespace_qualified>( &self, - local_namespaces: &BTreeMap, S>, + namespace_context: &BTreeMap, S>, ) -> bool { + // create a new local_namespaces combining that in the context and those declared within the element + let mut local_namespaces = *namespace_context.clone(); + self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration)); + if let Some(namespace) = local_namespaces.get(self.prefix) { if namespace != self.namespace { return false; } + } else { + 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 { + if child.namespace_qualified(&local_namespaces) == false { return false; } } @@ -267,6 +252,7 @@ impl Element { true } + /// 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, W: AsyncWrite + Unpin + Send>( @@ -274,7 +260,7 @@ impl Element { writer: &mut Writer, local_namespaces: &BTreeMap, S>, ) -> Result<()> { - // 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 + // TODO: 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 = self.into(); for event in events { @@ -553,17 +539,107 @@ impl Node { fn namespace_qualified>( &self, - local_namespaces: &BTreeMap, S>, + namespace_context: &BTreeMap, S>, ) -> bool { match self { - Self::Element(e) => e.namespace_qualified(local_namespaces), + Self::Element(e) => e.namespace_qualified(namespace_context), _ => true, } } } -// 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 +pub enum NodeBuilder { + Text(String), + Element(ElementBuilder), +} + +pub struct ElementBuilder { + localname: String, + prefix: Option, + namespace: String, + namespace_declarations: BTreeMap, String>, + attributes: BTreeMap, + children: Vec, +} + +impl ElementBuilder { + pub fn new(localname: S, prefix: Option, namespace: S) -> Self { + Self { + prefix, + localname, + namespace, + namespace_declarations: Box::new(BTreeMap::new()), + attributes: Box::new(BTreeMap::new()), + children: Box::new(Vec::new()), + } + } + + pub fn push_namespace_declaration( + &mut self, + (prefix, namespace): (Option, S), + ) -> Option { + self.namespace_declarations.insert(prefix, namespace) + } + + pub fn push_attribute(&mut self, (key, value): (S, S)) -> Option { + self.attributes.insert(key, value) + } + + pub fn push_child(&mut self, child: Node) { + self.children.push(child) + } + + /// checks if there is a namespace conflict within the element being built + pub fn namespace_conflict>( + &self + ) -> bool { + self.namespace_conflict_recursive(&BTreeMap::new()) + } + + fn namespace_conflict_recursive>( + &self, + parent_namespaces: &BTreeMap, S>, + ) -> bool { + // create a new local_namespaces combining that in the context and those declared within the element + let mut local_namespaces = *parent_namespaces.clone(); + self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration)); + + if let Some(namespace) = local_namespaces.get(self.prefix) { + if namespace != self.namespace { + return false; + } + } else { + return false; + }; + + for child in *self.children { + if child.namespace_conflict(&local_namespaces) == false { + return false; + } + } + + true + } + + // check for possible conflicts in namespace + pub fn build(self) -> Result { + for child in self.children { + match child { + Node::Element(e) => { + if !e.namespace_conflict() + } + } + } + Element { + prefix: self.prefix, + localname: self.localname, + namespace: self.namespace, + namespace_declarations: self.namespace_declarations, + attributes: self.attributes, + children: self.children, + } + } +} #[derive(Debug)] pub enum ElementError<'e> { -- cgit