WIP: refactor Element type - main architecture done

This commit is contained in:
cel 🌸 2023-08-05 17:38:50 +01:00
parent 8ab4a8b436
commit dec6f0105d
1 changed files with 187 additions and 46 deletions

View File

@ -11,6 +11,7 @@ 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::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::PrefixDeclaration;
use quick_xml::{Reader, Writer}; use quick_xml::{Reader, Writer};
use tokio::io::{AsyncBufRead, AsyncWrite}; use tokio::io::{AsyncBufRead, AsyncWrite};
@ -85,6 +86,7 @@ pub struct Element<'s> {
pub enum Node<'s> { pub enum Node<'s> {
Element(Element<'s>), Element(Element<'s>),
Text(&'s str), Text(&'s str),
Unknown,
} }
impl<'s> From<&Node<'s>> for Vec<Event<'s>> { impl<'s> From<&Node<'s>> for Vec<Event<'s>> {
@ -92,6 +94,7 @@ impl<'s> From<&Node<'s>> for Vec<Event<'s>> {
match node { match node {
Node::Element(e) => e.into(), Node::Element(e) => e.into(),
Node::Text(t) => vec![Event::Text(BytesText::new(t))], Node::Text(t) => vec![Event::Text(BytesText::new(t))],
Unknown => vec![],
} }
} }
} }
@ -182,16 +185,18 @@ impl<'s> From<&Element<'s>> for Vec<Event<'s>> {
impl<'s> Element<'s> { impl<'s> Element<'s> {
/// if there is only one child in the vec of children, will return that element /// if there is only one child in the vec of children, will return that element
pub fn child(&self) -> Result<&Element<'s>> { pub fn child(&self) -> Result<&Node<'s>> {
if self.children.len() == 1 { if self.children.len() == 1 {
Ok(&self.children[0]) Ok(&self.children[0])
} else if self.children.len() > 1 {
Err(ElementError::MultipleChildren.into())
} else { } else {
Err(ElementError::NoChildren.into()) Err(ElementError::NoChildren.into())
} }
} }
/// returns reference to children /// returns reference to children
pub fn children(&self) -> Result<&Vec<Element<'s>>> { pub fn children(&self) -> Result<&Vec<Node<'s>>> {
if !self.children.is_empty() { if !self.children.is_empty() {
Ok(&self.children) Ok(&self.children)
} else { } else {
@ -200,14 +205,18 @@ impl<'s> Element<'s> {
} }
/// returns text content, error if there is none /// returns text content, error if there is none
pub fn content(&self) -> Result<&str> { pub fn text_content(&self) -> Result<Vec<&str>> {
let text = Vec::new();
for node in *self.children { for node in *self.children {
match node { match node {
Node::Text(t) => return Ok(t), Node::Text(t) => text.push(t),
_ => {} _ => {}
} }
} }
Err(ElementError::NotText) if text.is_empty() {
Err(ElementError::NotText)
}
Ok(text)
} }
pub async fn write<W: AsyncWrite + Unpin + Send>(&self, writer: &mut Writer<W>) -> Result<()> { pub async fn write<W: AsyncWrite + Unpin + Send>(&self, writer: &mut Writer<W>) -> Result<()> {
@ -252,32 +261,11 @@ impl<'s> Element<'s> {
writer.write_event_async(Event::End(event)).await?; writer.write_event_async(Event::End(event)).await?;
Ok(()) Ok(())
} }
// 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>,
local_namespaces: BTreeMap<Option<&str>, &str>, local_namespaces: &BTreeMap<Option<&str>, &str>,
) -> Result<Self> { ) -> Result<Self> {
let node = Node::read_recursive(reader, local_namespaces) let node = Node::read_recursive(reader, local_namespaces)
.await? .await?
@ -285,16 +273,13 @@ impl<'s> Element<'s> {
match node { match node {
Node::Element(e) => Ok(e), Node::Element(e) => Ok(e),
Node::Text(_) => Err(JabberError::UnexpectedText), Node::Text(_) => Err(JabberError::UnexpectedText),
Node::Unknown => Err(JabberError::UnexpectedElement),
} }
} }
} pub async fn read_start<R: AsyncBufRead + Unpin + Send>(
impl<'s> Node<'s> {
#[async_recursion]
async fn read_recursive<R: AsyncBufRead + Unpin + Send>(
reader: &mut Reader<R>, reader: &mut Reader<R>,
local_namespaces: BTreeMap<Option<&str>, &str>, local_namespaces: &BTreeMap<Option<&str>, &str>,
) -> Result<Option<Node<'s>>> { ) -> Result<Self> {
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 {
@ -303,26 +288,176 @@ impl<'s> Node<'s> {
.name() .name()
.prefix() .prefix()
.map(|prefix| str::from_utf8(prefix.into_inner())?); .map(|prefix| str::from_utf8(prefix.into_inner())?);
let localname = str::from_utf8(e.local_name().into_inner())?;
let mut children_vec: Vec = Vec::new(); let mut namespaces = local_namespaces.clone();
while let Some(sub_element) = Element::read_recursive(reader).await? { let mut namespace_declarations = BTreeMap::new();
children_vec.push(sub_element) let attributes = BTreeMap::new();
for attribute in e.attributes() {
let attribute = attribute?;
if let Some(prefix_declaration) = attribute.key.as_namespace_binding() {
match prefix_declaration {
PrefixDeclaration::Default => {
let value = str::from_utf8(attribute.value.as_ref())?;
namespace_declarations.try_insert(None, value);
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);
}
}
} else {
attributes
.try_insert(
str::from_utf8(attribute.key.into_inner())?,
str::from_utf8(attribute.value.as_ref())?,
)
.map_err(ParseError::DuplicateAttribute)?;
}
} }
let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?;
let mut children = Vec::new();
Ok(Some(Self::Element(Element { Ok(Some(Self::Element(Element {
prefix, prefix,
localname: e.local_name().into_inner(), localname,
namespace: todo!(), namespace,
namespace_declarations: todo!(), namespace_declarations,
attributes: todo!(), attributes,
children: todo!(), children,
})))
}
e => Err(ElementError::NotAStart(e)),
}
}
}
impl<'s> Node<'s> {
async fn read_recursive<R: AsyncBufRead + Unpin + Send>(
reader: &mut Reader<R>,
local_namespaces: &BTreeMap<Option<&str>, &str>,
) -> Result<Option<Node<'s>>> {
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 mut namespaces = local_namespaces.clone();
let mut namespace_declarations = BTreeMap::new();
let attributes = BTreeMap::new();
for attribute in e.attributes() {
let attribute = attribute?;
if let Some(prefix_declaration) = attribute.key.as_namespace_binding() {
match prefix_declaration {
PrefixDeclaration::Default => {
let value = str::from_utf8(attribute.value.as_ref())?;
namespace_declarations.try_insert(None, value);
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);
}
}
} else {
attributes
.try_insert(
str::from_utf8(attribute.key.into_inner())?,
str::from_utf8(attribute.value.as_ref())?,
)
.map_err(ParseError::DuplicateAttribute)?;
}
}
let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?;
let children = Vec::new();
Ok(Some(Self::Element(Element {
prefix,
localname,
namespace,
namespace_declarations,
attributes,
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 mut namespaces = local_namespaces.clone();
let mut namespace_declarations = BTreeMap::new();
let attributes = BTreeMap::new();
for attribute in e.attributes() {
let attribute = attribute?;
if let Some(prefix_declaration) = attribute.key.as_namespace_binding() {
match prefix_declaration {
PrefixDeclaration::Default => {
let value = str::from_utf8(attribute.value.as_ref())?;
namespace_declarations.try_insert(None, value);
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);
}
}
} else {
attributes
.try_insert(
str::from_utf8(attribute.key.into_inner())?,
str::from_utf8(attribute.value.as_ref())?,
)
.map_err(ParseError::DuplicateAttribute)?;
}
}
let namespace = *namespaces.get(&prefix).ok_or(ParseError::NoNamespace)?;
let mut children = Vec::new();
while let Some(child_node) = Node::read_recursive(reader, &namespaces).await? {
children.push(child_node)
}
Ok(Some(Self::Element(Element {
prefix,
localname,
namespace,
namespace_declarations,
attributes,
children,
}))) })))
} }
Event::End(_) => Ok(None), 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()))),
e => Ok(Some(Self { e => Ok(Some(Self::Unknown)),
event: e.into_owned(),
children: None,
})),
} }
} }
} }
@ -365,3 +500,9 @@ pub enum ElementError<'e> {
NoChildren, NoChildren,
MultipleChildren, MultipleChildren,
} }
#[derive(Debug)]
pub enum ParseError {
DuplicateAttribute,
NoNamespace,
}