summaryrefslogtreecommitdiffstats
path: root/src/stanza/mod.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-10-20 02:34:47 +0100
committerLibravatar cel 🌸 <cel@blos.sm>2023-10-20 02:34:47 +0100
commit2536fa4937f0283b4187142cc6cede8e1dbfafa8 (patch)
treee62edc29e91a5574e4a35b96745c9454d8bf88a1 /src/stanza/mod.rs
parentb4652b3939858306806d48781fb7c7b1ec52ad1d (diff)
downloadluz-2536fa4937f0283b4187142cc6cede8e1dbfafa8.tar.gz
luz-2536fa4937f0283b4187142cc6cede8e1dbfafa8.tar.bz2
luz-2536fa4937f0283b4187142cc6cede8e1dbfafa8.zip
WIP: mess
Diffstat (limited to '')
-rw-r--r--src/stanza/mod.rs132
1 files changed, 104 insertions, 28 deletions
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<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 {
Element(Element),
@@ -244,22 +229,22 @@ impl Element {
/// by a parent, or itself.
fn namespace_qualified<S: AsRef<str>>(
&self,
- local_namespaces: &BTreeMap<Option<S>, S>,
+ namespace_context: &BTreeMap<Option<S>, 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<S: AsRef<str>, W: AsyncWrite + Unpin + Send>(
@@ -274,7 +260,7 @@ impl Element {
writer: &mut Writer<W>,
local_namespaces: &BTreeMap<Option<S>, 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<Event> = self.into();
for event in events {
@@ -553,17 +539,107 @@ impl Node {
fn namespace_qualified<S: AsRef<str>>(
&self,
- local_namespaces: &BTreeMap<Option<S>, S>,
+ namespace_context: &BTreeMap<Option<S>, 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<String>,
+ namespace: String,
+ namespace_declarations: BTreeMap<Option<String>, String>,
+ attributes: BTreeMap<String, String>,
+ children: Vec<NodeBuilder>,
+}
+
+impl ElementBuilder {
+ pub fn new<S: ToString>(localname: S, prefix: Option<S>, 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<S: ToString>(
+ &mut self,
+ (prefix, namespace): (Option<S>, S),
+ ) -> Option<S> {
+ self.namespace_declarations.insert(prefix, namespace)
+ }
+
+ pub fn push_attribute<S: ToString>(&mut self, (key, value): (S, S)) -> Option<S> {
+ 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<S: AsRef<str>>(
+ &self
+ ) -> bool {
+ self.namespace_conflict_recursive(&BTreeMap::new())
+ }
+
+ fn namespace_conflict_recursive<S: AsRef<str>>(
+ &self,
+ parent_namespaces: &BTreeMap<Option<S>, 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<Element> {
+ 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> {