From 87ac9a12271404e1ba046187ee47d178f2d88b3c Mon Sep 17 00:00:00 2001 From: lumi Date: Sun, 19 Feb 2017 18:08:35 +0100 Subject: [PATCH] cleanups and initial XML tree implementation --- src/client.rs | 11 ++-- src/error.rs | 1 + src/lib.rs | 1 + src/transport.rs | 13 ++++ src/tree.rs | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 src/tree.rs diff --git a/src/client.rs b/src/client.rs index de3b84f..d01b921 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,7 +3,8 @@ use transport::{Transport, SslTransport}; use error::Error; use ns; -use xml::writer::XmlEvent; +use xml::writer::XmlEvent as WriterEvent; +use xml::reader::XmlEvent as ReaderEvent; pub struct ClientBuilder { jid: Jid, @@ -33,10 +34,10 @@ impl ClientBuilder { pub fn connect(self) -> Result { let host = &self.host.unwrap_or(self.jid.domain.clone()); let mut transport = SslTransport::connect(host, self.port)?; - transport.write_event(XmlEvent::start_element("stream:stream") - .attr("to", &self.jid.domain) - .default_ns(ns::CLIENT) - .ns("stream", ns::STREAM))?; + transport.write_event(WriterEvent::start_element("stream:stream") + .attr("to", &self.jid.domain) + .default_ns(ns::CLIENT) + .ns("stream", ns::STREAM))?; Ok(Client { jid: self.jid, transport: transport diff --git a/src/error.rs b/src/error.rs index 1646fff..f4af81d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,7 @@ pub enum Error { HandshakeError(HandshakeError), OpenSslErrorStack(ErrorStack), StreamError, + EndOfDocument, } impl From for Error { diff --git a/src/lib.rs b/src/lib.rs index ea726d5..08a2997 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,5 +6,6 @@ pub mod transport; pub mod error; pub mod jid; pub mod client; +pub mod tree; mod locked_io; diff --git a/src/transport.rs b/src/transport.rs index cd7aa3e..b7b299d 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -9,6 +9,8 @@ use std::sync::{Arc, Mutex}; use ns; +use tree; + use locked_io::LockedIO; use error::Error; @@ -18,6 +20,9 @@ use openssl::ssl::{SslMethod, SslConnectorBuilder, SslStream}; pub trait Transport { fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error>; fn read_event(&mut self) -> Result; + + fn write_element(&mut self, element: &tree::Element) -> Result<(), Error>; + fn read_element(&mut self) -> Result; } pub struct SslTransport { @@ -36,6 +41,14 @@ impl Transport for SslTransport { fn read_event(&mut self) -> Result { Ok(self.reader.next()?) } + + fn write_element(&mut self, element: &tree::Element) -> Result<(), Error> { + element.write_to(&mut self.writer) + } + + fn read_element(&mut self) -> Result { + tree::Element::from_reader(&mut self.reader) + } } impl SslTransport { diff --git a/src/tree.rs b/src/tree.rs new file mode 100644 index 0000000..af3591f --- /dev/null +++ b/src/tree.rs @@ -0,0 +1,164 @@ +// TODO: really should either be a separate crate or implemented into xml-rs + +use std::io::prelude::*; + +use std::fmt; + +use xml::name::{OwnedName, Name}; +use xml::reader::{XmlEvent, EventReader}; +use xml::writer::{XmlEvent as WriterEvent, EventWriter}; +use xml::attribute::OwnedAttribute; + +use error::Error; + +#[derive(Clone)] +pub struct Element { + name: OwnedName, + attributes: Vec, + children: Vec, +} + +impl fmt::Debug for Element { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "<{}", self.name)?; + for attr in &self.attributes { + write!(fmt, " {}", attr)?; + } + write!(fmt, ">")?; + for child in &self.children { + match *child { + Fork::Element(ref e) => { + write!(fmt, "{:?}", e)?; + }, + Fork::Text(ref s) => { + write!(fmt, "{}", s)?; + }, + } + } + write!(fmt, "", self.name)?; + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub enum Fork { + Element(Element), + Text(String), +} + +impl Element { + pub fn new(name: OwnedName, attributes: Vec) -> Element { + Element { + name: name, + attributes: attributes, + children: Vec::new(), + } + } + + pub fn from_reader(reader: &mut EventReader) -> Result { + loop { + let e = reader.next()?; + match e { + XmlEvent::StartElement { name, attributes, .. } => { + let mut root = Element::new(name, attributes); + root.from_reader_inner(reader); + return Ok(root); + }, + XmlEvent::EndDocument => { + return Err(Error::EndOfDocument); + }, + _ => () // TODO: may need more errors + } + } + } + + fn from_reader_inner(&mut self, reader: &mut EventReader) -> Result<(), Error> { + loop { + let e = reader.next()?; + match e { + XmlEvent::StartElement { name, attributes, .. } => { + let elem = Element::new(name, attributes); + let elem_ref = self.append_child(elem); + elem_ref.from_reader_inner(reader); + }, + XmlEvent::EndElement { .. } => { + // TODO: may want to check whether we're closing the correct element + return Ok(()); + }, + XmlEvent::Characters(s) => { + self.append_text_node(s); + }, + XmlEvent::CData(s) => { + self.append_text_node(s); + }, + XmlEvent::EndDocument => { + return Err(Error::EndOfDocument); + }, + _ => (), // TODO: may need to implement more + } + } + } + + pub fn write_to(&self, writer: &mut EventWriter) -> Result<(), Error> { + let start = WriterEvent::start_element(self.name.borrow()); + writer.write(start)?; + for child in &self.children { + match *child { + Fork::Element(ref e) => { + e.write_to(writer)?; + }, + Fork::Text(ref s) => { + writer.write(WriterEvent::characters(s))?; + }, + } + } + writer.write(WriterEvent::end_element())?; + Ok(()) + } + + pub fn children<'a>(&'a self) -> Children<'a> { + unimplemented!(); + } + + pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> { + unimplemented!(); + } + + pub fn append_child(&mut self, child: Element) -> &mut Element { + self.children.push(Fork::Element(child)); + if let Fork::Element(ref mut cld) = *self.children.last_mut().unwrap() { + cld + } + else { + unreachable!() + } + } + + pub fn append_text_node(&mut self, child: String) { + self.children.push(Fork::Text(child)); + } + + pub fn text(&self) -> &str { + unimplemented!() + } + + pub fn get_child<'a, N: Into>>(&self, name: N) -> Option<&Element> { + unimplemented!() + } + + pub fn get_child_mut<'a, N: Into>>(&mut self, name: N) -> Option<&mut Element> { + unimplemented!() + } + + pub fn into_child<'a, N: Into>>(self, name: N) -> Option { + unimplemented!() + } +} + +pub struct Children<'a> { + elem: &'a Element, +} + +pub struct ChildrenMut<'a> { + elem: &'a mut Element, +}