1
0
mirror of https://gitlab.com/xmpp-rs/xmpp-rs.git synced 2024-06-02 14:29:20 +02:00

cargo fmt

This commit is contained in:
Astro 2022-03-25 18:50:23 +01:00
parent 14653c1396
commit d976200302
6 changed files with 314 additions and 286 deletions

View File

@ -96,4 +96,4 @@ pub use error::{Error, Result};
pub use namespaces::NSChoice; pub use namespaces::NSChoice;
pub use node::Node; pub use node::Node;
pub use token::Token; pub use token::Token;
pub use tokenizer::{Tokenizer, TokenizerError, tokenize}; pub use tokenizer::{tokenize, Tokenizer, TokenizerError};

View File

@ -1,15 +1,18 @@
//! Parsed XML token //! Parsed XML token
use std::borrow::Cow;
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::streaming::{tag, take_while1}, bytes::streaming::{tag, take_while1},
character::{is_space, streaming::{char, digit1, one_of, space0, space1}}, character::{
is_space,
streaming::{char, digit1, one_of, space0, space1},
},
combinator::{not, peek, value}, combinator::{not, peek, value},
multi::many0, multi::many0,
number::streaming::hex_u32, number::streaming::hex_u32,
IResult, IResult,
}; };
use std::borrow::Cow;
/// Attribute name with prefix /// Attribute name with prefix
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
@ -23,16 +26,14 @@ pub struct LocalName {
impl From<&str> for LocalName { impl From<&str> for LocalName {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
match s.split_once(':') { match s.split_once(':') {
Some((prefix, name)) => Some((prefix, name)) => LocalName {
LocalName { prefix: Some(prefix.to_owned()),
prefix: Some(prefix.to_owned()), name: name.to_owned(),
name: name.to_owned(), },
}, None => LocalName {
None => prefix: None,
LocalName { name: s.to_owned(),
prefix: None, },
name: s.to_owned(),
},
} }
} }
} }
@ -75,97 +76,109 @@ pub enum Token {
impl Token { impl Token {
/// Parse one token /// Parse one token
pub fn parse(s: &[u8]) -> IResult<&[u8], Token> { pub fn parse(s: &[u8]) -> IResult<&[u8], Token> {
alt(( alt((Self::parse_tag, |s| {
Self::parse_tag, let (s, _) = not(peek(char('<')))(s)?;
|s| { let (s, text) = Self::parse_text('<', s)?;
let (s, _) = not(peek(char('<')))(s)?; Ok((s, Token::Text(text.into_owned())))
let (s, text) = Self::parse_text('<', s)?; }))(s)
Ok((s, Token::Text(text.into_owned())))
},
))(s)
} }
fn parse_tag(s: &[u8]) -> IResult<&[u8], Token> { fn parse_tag(s: &[u8]) -> IResult<&[u8], Token> {
let (s, _) = tag("<")(s)?; let (s, _) = tag("<")(s)?;
alt((|s| -> IResult<&[u8], Token> { alt((
// CDATA |s| -> IResult<&[u8], Token> {
let (s, _) = tag("![CDATA[")(s)?; // CDATA
let mut end = None; let (s, _) = tag("![CDATA[")(s)?;
for i in 0..s.len() - 2 { let mut end = None;
if &s[i..i + 3] == b"]]>" { for i in 0..s.len() - 2 {
end = Some(i); if &s[i..i + 3] == b"]]>" {
break end = Some(i);
break;
}
} }
} if let Some(end) = end {
if let Some(end) = end { let text = Self::str_from_utf8(&s[..end])?;
let text = Self::str_from_utf8(&s[..end])?; Ok((&s[end + 3..], Token::Text(text.to_string())))
Ok((&s[end + 3..], Token::Text(text.to_string()))) } else {
} else { Err(nom::Err::Incomplete(nom::Needed::Unknown))
Err(nom::Err::Incomplete(nom::Needed::Unknown)) }
} },
}, |s| { |s| {
// XmlDecl // XmlDecl
let (s, _) = tag("?xml")(s)?; let (s, _) = tag("?xml")(s)?;
let (s, _) = space1(s)?; let (s, _) = space1(s)?;
let (s, attrs) = many0(|s| {
let (s, (name, value)) = Self::parse_attr(s)?;
let (s, _) = space0(s)?;
Ok((s, (name, value)))
})(s)?;
let (s, attrs) = many0(|s| {
let (s, (name, value)) = Self::parse_attr(s)?;
let (s, _) = space0(s)?; let (s, _) = space0(s)?;
Ok((s, (name, value))) let (s, _) = tag("?>")(s)?;
})(s)?; Ok((
s,
let (s, _) = space0(s)?; Token::XmlDecl {
let (s, _) = tag("?>")(s)?; attrs: attrs
Ok((s, Token::XmlDecl { .into_iter()
attrs: attrs.into_iter() .map(|(name, value)| Attribute {
.map(|(name, value)| Attribute { name: name.into(),
name: name.into(), value: value.into_owned(),
value: value.into_owned(), })
}) .collect(),
.collect(), },
})) ))
}, |s| { },
// EndTag |s| {
let (s, _) = tag("/")(s)?; // EndTag
let (s, _) = space0(s)?;
let (s, name) = take_while1(|b| !(is_space(b) || b == b'>'))(s)?;
let (s, _) = space0(s)?;
let (s, _) = tag(">")(s)?;
let name = Self::str_from_utf8(name)?;
Ok((s, Token::EndTag { name: name.into() }))
}, |s| {
// StartTag
let (s, _) = space0(s)?;
let (s, name) = take_while1(|b| !(is_space(b) || b == b'>' || b == b'/'))(s)?;
let (s, _) = space0(s)?;
let (s, attrs) = many0(|s| {
let (s, (name, value)) = Self::parse_attr(s)?;
let (s, _) = space0(s)?;
Ok((s, (name, value)))
})(s)?;
let (s, self_closing) = alt((|s| {
let (s, _) = tag("/")(s)?; let (s, _) = tag("/")(s)?;
let (s, _) = space0(s)?; let (s, _) = space0(s)?;
let (s, name) = take_while1(|b| !(is_space(b) || b == b'>'))(s)?;
let (s, _) = space0(s)?;
let (s, _) = tag(">")(s)?; let (s, _) = tag(">")(s)?;
Ok((s, true)) let name = Self::str_from_utf8(name)?;
}, |s| { Ok((s, Token::EndTag { name: name.into() }))
let (s, _) = tag(">")(s)?; },
Ok((s, false)) |s| {
}))(s)?; // StartTag
let (s, _) = space0(s)?;
let (s, name) = take_while1(|b| !(is_space(b) || b == b'>' || b == b'/'))(s)?;
let (s, _) = space0(s)?;
let (s, attrs) = many0(|s| {
let (s, (name, value)) = Self::parse_attr(s)?;
let (s, _) = space0(s)?;
Ok((s, (name, value)))
})(s)?;
Ok((s, Token::StartTag { let (s, self_closing) = alt((
name: Self::str_from_utf8(name)? |s| {
.into(), let (s, _) = tag("/")(s)?;
attrs: attrs.into_iter() let (s, _) = space0(s)?;
.map(|(name, value)| Attribute { let (s, _) = tag(">")(s)?;
name: name.into(), Ok((s, true))
value: value.into_owned(), },
}) |s| {
.collect(), let (s, _) = tag(">")(s)?;
self_closing, Ok((s, false))
})) },
}))(s) ))(s)?;
Ok((
s,
Token::StartTag {
name: Self::str_from_utf8(name)?.into(),
attrs: attrs
.into_iter()
.map(|(name, value)| Attribute {
name: name.into(),
value: value.into_owned(),
})
.collect(),
self_closing,
},
))
},
))(s)
} }
fn parse_attr(s: &[u8]) -> IResult<&[u8], (&str, Cow<str>)> { fn parse_attr(s: &[u8]) -> IResult<&[u8], (&str, Cow<str>)> {
@ -182,54 +195,51 @@ impl Token {
} }
fn parse_text(until: char, s: &[u8]) -> IResult<&[u8], Cow<str>> { fn parse_text(until: char, s: &[u8]) -> IResult<&[u8], Cow<str>> {
let (s, results) = many0( let (s, results) = many0(alt((
alt( |s| {
(|s| { let (s, _) = tag("&#")(s)?;
let (s, _) = tag("&#")(s)?; let (s, num) = digit1(s)?;
let (s, num) = digit1(s)?; let (s, _) = char(';')(s)?;
let (s, _) = char(';')(s)?; let num: u32 = Self::str_from_utf8(num)?.parse().map_err(|_| {
let num: u32 = Self::str_from_utf8(num)? nom::Err::Failure(nom::error::Error::new(s, nom::error::ErrorKind::Fail))
.parse() })?;
.map_err(|_| nom::Err::Failure(nom::error::Error::new(s, nom::error::ErrorKind::Fail)))?; if let Some(c) = std::char::from_u32(num) {
if let Some(c) = std::char::from_u32(num) {
Ok((s, Cow::from(format!("{}", c))))
} else {
Ok((s, Cow::from(format!(""))))
}
}, |s| {
let (s, _) = tag("&#x")(s)?;
let (s, num) = hex_u32(s)?;
let (s, _) = char(';')(s)?;
if let Some(c) = std::char::from_u32(num) {
Ok((s, Cow::from(format!("{}", c))))
} else {
Ok((s, Cow::from(format!(""))))
}
}, |s| {
let (s, _) = char('&')(s)?;
let (s, c) = alt((
value('&', tag("amp")),
value('<', tag("lt")),
value('>', tag("gt")),
value('"', tag("quot")),
value('\'', tag("apos")),
))(s)?;
let (s, _) = char(';')(s)?;
Ok((s, Cow::from(format!("{}", c)))) Ok((s, Cow::from(format!("{}", c))))
}, |s| { } else {
let (s, _) = not(peek(char(until)))(s)?; Ok((s, Cow::from(format!(""))))
let (s, text) = take_while1(|b| }
b != until as u8 && },
b != b'&' && |s| {
b != b'<' && let (s, _) = tag("&#x")(s)?;
b != b'>' let (s, num) = hex_u32(s)?;
)(s)?; let (s, _) = char(';')(s)?;
let text = Self::str_from_utf8(text)?; if let Some(c) = std::char::from_u32(num) {
let text = Self::normalize_newlines(text); Ok((s, Cow::from(format!("{}", c))))
Ok((s, text)) } else {
}) Ok((s, Cow::from(format!(""))))
) }
)(s)?; },
|s| {
let (s, _) = char('&')(s)?;
let (s, c) = alt((
value('&', tag("amp")),
value('<', tag("lt")),
value('>', tag("gt")),
value('"', tag("quot")),
value('\'', tag("apos")),
))(s)?;
let (s, _) = char(';')(s)?;
Ok((s, Cow::from(format!("{}", c))))
},
|s| {
let (s, _) = not(peek(char(until)))(s)?;
let (s, text) =
take_while1(|b| b != until as u8 && b != b'&' && b != b'<' && b != b'>')(s)?;
let text = Self::str_from_utf8(text)?;
let text = Self::normalize_newlines(text);
Ok((s, text))
},
)))(s)?;
if results.len() == 1 { if results.len() == 1 {
Ok((s, results.into_iter().next().unwrap())) Ok((s, results.into_iter().next().unwrap()))
@ -329,11 +339,14 @@ mod tests {
#[test] #[test]
fn test_tag() { fn test_tag() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "foobar".into(), &b""[..],
attrs: vec![], Token::StartTag {
self_closing: false, name: "foobar".into(),
})), attrs: vec![],
self_closing: false,
}
)),
Token::parse(b"<foobar>") Token::parse(b"<foobar>")
); );
} }
@ -341,15 +354,14 @@ mod tests {
#[test] #[test]
fn test_attrs() { fn test_attrs() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "a".into(), &b""[..],
attrs: vec![ Token::StartTag {
attr("a", "2'3"), name: "a".into(),
attr("b", "4\"2"), attrs: vec![attr("a", "2'3"), attr("b", "4\"2"), attr("c", ""),],
attr("c", ""), self_closing: false,
], }
self_closing: false, )),
})),
Token::parse(b"<a a=\"2'3\" b = '4\"2' c = ''>") Token::parse(b"<a a=\"2'3\" b = '4\"2' c = ''>")
); );
} }
@ -357,15 +369,14 @@ mod tests {
#[test] #[test]
fn test_attrs_normalized() { fn test_attrs_normalized() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "a".into(), &b""[..],
attrs: vec![ Token::StartTag {
attr("a", "x y"), name: "a".into(),
attr("b", " "), attrs: vec![attr("a", "x y"), attr("b", " "), attr("c", "a b"),],
attr("c", "a b"), self_closing: false,
], }
self_closing: false, )),
})),
Token::parse(b"<a a=\"x\ty\" b = '\r\n' c = 'a\r\rb'>") Token::parse(b"<a a=\"x\ty\" b = '\r\n' c = 'a\r\rb'>")
); );
} }
@ -373,13 +384,14 @@ mod tests {
#[test] #[test]
fn test_attrs_entities() { fn test_attrs_entities() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "a".into(), &b""[..],
attrs: vec![ Token::StartTag {
attr("a", "<3"), name: "a".into(),
], attrs: vec![attr("a", "<3"),],
self_closing: false, self_closing: false,
})), }
)),
Token::parse(b"<a a='&lt;&#51;'>") Token::parse(b"<a a='&lt;&#51;'>")
); );
} }
@ -387,11 +399,14 @@ mod tests {
#[test] #[test]
fn test_self_closing_tag() { fn test_self_closing_tag() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "foobar".into(), &b""[..],
attrs: vec![], Token::StartTag {
self_closing: true, name: "foobar".into(),
})), attrs: vec![],
self_closing: true,
}
)),
Token::parse(b"<foobar/>") Token::parse(b"<foobar/>")
); );
} }
@ -399,9 +414,12 @@ mod tests {
#[test] #[test]
fn test_end_tag() { fn test_end_tag() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::EndTag { Ok((
name: "foobar".into(), &b""[..],
})), Token::EndTag {
name: "foobar".into(),
}
)),
Token::parse(b"</foobar>") Token::parse(b"</foobar>")
); );
} }
@ -409,14 +427,17 @@ mod tests {
#[test] #[test]
fn test_element_prefix() { fn test_element_prefix() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: LocalName { &b""[..],
name: "z".to_owned(), Token::StartTag {
prefix: Some("x".to_owned()), name: LocalName {
}, name: "z".to_owned(),
attrs: vec![], prefix: Some("x".to_owned()),
self_closing: true, },
})), attrs: vec![],
self_closing: true,
}
)),
Token::parse(b"<x:z/>") Token::parse(b"<x:z/>")
); );
} }
@ -424,17 +445,20 @@ mod tests {
#[test] #[test]
fn test_attr_prefix() { fn test_attr_prefix() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::StartTag { Ok((
name: "a".into(), &b""[..],
attrs: vec![Attribute { Token::StartTag {
name: LocalName { name: "a".into(),
name: "abc".to_owned(), attrs: vec![Attribute {
prefix: Some("xyz".to_owned()), name: LocalName {
}, name: "abc".to_owned(),
value: "".to_owned(), prefix: Some("xyz".to_owned()),
}], },
self_closing: false, value: "".to_owned(),
})), }],
self_closing: false,
}
)),
Token::parse(b"<a xyz:abc=''>") Token::parse(b"<a xyz:abc=''>")
); );
} }
@ -442,21 +466,27 @@ mod tests {
#[test] #[test]
fn test_xml_decl() { fn test_xml_decl() {
assert_eq!( assert_eq!(
Ok((&b""[..], Token::XmlDecl { Ok((
attrs: vec![Attribute { &b""[..],
name: LocalName { Token::XmlDecl {
name: "version".to_owned(), attrs: vec![
prefix: None, Attribute {
}, name: LocalName {
value: "1.0".to_owned(), name: "version".to_owned(),
}, Attribute { prefix: None,
name: LocalName { },
name: "encoding".to_owned(), value: "1.0".to_owned(),
prefix: None, },
}, Attribute {
value: "UTF-8".to_owned(), name: LocalName {
}], name: "encoding".to_owned(),
})), prefix: None,
},
value: "UTF-8".to_owned(),
}
],
}
)),
Token::parse(b"<?xml version='1.0' encoding=\"UTF-8\"?>") Token::parse(b"<?xml version='1.0' encoding=\"UTF-8\"?>")
); );
} }

View File

@ -2,8 +2,8 @@
//! Streaming tokenizer (SAX parser) //! Streaming tokenizer (SAX parser)
use bytes::BytesMut;
use super::{Error, Token}; use super::{Error, Token};
use bytes::BytesMut;
/// `Result::Err` type returned from `Tokenizer` /// `Result::Err` type returned from `Tokenizer`
pub type TokenizerError = nom::error::Error<String>; pub type TokenizerError = nom::error::Error<String>;
@ -55,26 +55,23 @@ pub fn tokenize(buffer: &mut BytesMut) -> Result<Option<Token>, Error> {
} }
} }
let result: Option<(usize, Token)> = { match Token::parse(&buffer) { let result: Option<(usize, Token)> = {
Ok((s, token)) => match Token::parse(&buffer) {
Some((s.len(), token)), Ok((s, token)) => Some((s.len(), token)),
Result::Err(nom::Err::Incomplete(_)) => Result::Err(nom::Err::Incomplete(_)) => None,
None, Result::Err(nom::Err::Error(e)) => return Err(with_input_to_owned(e).into()),
Result::Err(nom::Err::Error(e)) => Result::Err(nom::Err::Failure(e)) => return Err(with_input_to_owned(e).into()),
return Err(with_input_to_owned(e).into()), }
Result::Err(nom::Err::Failure(e)) => };
return Err(with_input_to_owned(e).into()),
} };
match result { match result {
Some((s_len, token)) => { Some((s_len, token)) => {
let _ = buffer.split_to(buffer.len() - s_len); let _ = buffer.split_to(buffer.len() - s_len);
Ok(Some(token)) Ok(Some(token))
} }
None => Ok(None) None => Ok(None),
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -101,20 +98,21 @@ mod tests {
let buf = b"<foo bar='baz'>quux</foo>"; let buf = b"<foo bar='baz'>quux</foo>";
for chunk_size in 1..=buf.len() { for chunk_size in 1..=buf.len() {
assert_eq!(vec![ assert_eq!(
Token::StartTag { vec![
name: "foo".into(), Token::StartTag {
attrs: vec![Attribute { name: "foo".into(),
name: "bar".into(), attrs: vec![Attribute {
value: "baz".to_owned(), name: "bar".into(),
}], value: "baz".to_owned(),
self_closing: false, }],
}, self_closing: false,
Token::Text("quux".to_owned()), },
Token::EndTag { Token::Text("quux".to_owned()),
name: "foo".into(), Token::EndTag { name: "foo".into() },
}, ],
], run(chunk_size, buf)); run(chunk_size, buf)
);
} }
} }
} }

View File

@ -2,10 +2,10 @@
//! SAX events to DOM tree conversion //! SAX events to DOM tree conversion
use std::collections::BTreeMap;
use crate::{Element, Error};
use crate::prefixes::Prefixes; use crate::prefixes::Prefixes;
use crate::token::{Attribute, LocalName, Token}; use crate::token::{Attribute, LocalName, Token};
use crate::{Element, Error};
use std::collections::BTreeMap;
/// Tree-building parser state /// Tree-building parser state
pub struct TreeBuilder { pub struct TreeBuilder {
@ -85,7 +85,8 @@ impl TreeBuilder {
} }
self.prefixes_stack.push(prefixes.clone()); self.prefixes_stack.push(prefixes.clone());
let namespace = self.lookup_prefix(&name.prefix) let namespace = self
.lookup_prefix(&name.prefix)
.ok_or(Error::MissingNamespace)? .ok_or(Error::MissingNamespace)?
.to_owned(); .to_owned();
let el = Element::new( let el = Element::new(
@ -94,7 +95,7 @@ impl TreeBuilder {
Some(name.prefix), Some(name.prefix),
prefixes, prefixes,
attributes, attributes,
vec![] vec![],
); );
self.stack.push(el); self.stack.push(el);
@ -128,7 +129,7 @@ impl TreeBuilder {
/// Process a Token that you got out of a Tokenizer /// Process a Token that you got out of a Tokenizer
pub fn process_token(&mut self, token: Token) -> Result<(), Error> { pub fn process_token(&mut self, token: Token) -> Result<(), Error> {
match token { match token {
Token::XmlDecl { .. } => {}, Token::XmlDecl { .. } => {}
Token::StartTag { Token::StartTag {
name, name,
@ -145,11 +146,9 @@ impl TreeBuilder {
self.process_end_tag(name)?; self.process_end_tag(name)?;
} }
Token::EndTag { name } => Token::EndTag { name } => self.process_end_tag(name)?,
self.process_end_tag(name)?,
Token::Text(text) => Token::Text(text) => self.process_text(text),
self.process_text(text),
} }
Ok(()) Ok(())

View File

@ -203,30 +203,28 @@ impl Stream for Client {
self.poll_next(cx) self.poll_next(cx)
} }
ClientState::Disconnected => Poll::Ready(None), ClientState::Disconnected => Poll::Ready(None),
ClientState::Connecting(mut connect) => { ClientState::Connecting(mut connect) => match Pin::new(&mut connect).poll(cx) {
match Pin::new(&mut connect).poll(cx) { Poll::Ready(Ok(Ok(stream))) => {
Poll::Ready(Ok(Ok(stream))) => { let bound_jid = stream.jid.clone();
let bound_jid = stream.jid.clone(); self.state = ClientState::Connected(stream);
self.state = ClientState::Connected(stream); Poll::Ready(Some(Event::Online {
Poll::Ready(Some(Event::Online { bound_jid,
bound_jid, resumed: false,
resumed: false, }))
}))
}
Poll::Ready(Ok(Err(e))) => {
self.state = ClientState::Disconnected;
return Poll::Ready(Some(Event::Disconnected(e.into())));
}
Poll::Ready(Err(e)) => {
self.state = ClientState::Disconnected;
panic!("connect task: {}", e);
}
Poll::Pending => {
self.state = ClientState::Connecting(connect);
Poll::Pending
}
} }
} Poll::Ready(Ok(Err(e))) => {
self.state = ClientState::Disconnected;
return Poll::Ready(Some(Event::Disconnected(e.into())));
}
Poll::Ready(Err(e)) => {
self.state = ClientState::Disconnected;
panic!("connect task: {}", e);
}
Poll::Pending => {
self.state = ClientState::Connecting(connect);
Poll::Pending
}
},
ClientState::Connected(mut stream) => { ClientState::Connected(mut stream) => {
// Poll sink // Poll sink
match Pin::new(&mut stream).poll_ready(cx) { match Pin::new(&mut stream).poll_ready(cx) {

View File

@ -1,7 +1,9 @@
//! XML stream parser for XMPP //! XML stream parser for XMPP
use crate::Error;
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use log::debug; use log::debug;
use minidom::{tokenize, tree_builder::TreeBuilder};
use std; use std;
use std::collections::HashMap; use std::collections::HashMap;
use std::default::Default; use std::default::Default;
@ -9,8 +11,6 @@ use std::fmt::Write;
use std::io; use std::io;
use tokio_util::codec::{Decoder, Encoder}; use tokio_util::codec::{Decoder, Encoder};
use xmpp_parsers::Element; use xmpp_parsers::Element;
use minidom::{tokenize, tree_builder::TreeBuilder};
use crate::Error;
/// Anything that can be sent or received on an XMPP/XML stream /// Anything that can be sent or received on an XMPP/XML stream
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -60,20 +60,23 @@ impl Decoder for XMPPCodec {
self.stanza_builder.process_token(token)?; self.stanza_builder.process_token(token)?;
let has_stream_root = self.stanza_builder.depth() > 0; let has_stream_root = self.stanza_builder.depth() > 0;
if ! had_stream_root && has_stream_root { if !had_stream_root && has_stream_root {
let root = self.stanza_builder.top().unwrap(); let root = self.stanza_builder.top().unwrap();
let attrs = root.attrs() let attrs =
.map(|(name, value)| (name.to_owned(), value.to_owned())) root.attrs()
.chain( .map(|(name, value)| (name.to_owned(), value.to_owned()))
root.prefixes.declared_prefixes() .chain(root.prefixes.declared_prefixes().iter().map(
.iter() |(prefix, namespace)| {
.map(|(prefix, namespace)| ( (
prefix.as_ref().map(|prefix| format!("xmlns:{}", prefix)) prefix
.unwrap_or_else(|| "xmlns".to_owned()), .as_ref()
namespace.clone() .map(|prefix| format!("xmlns:{}", prefix))
)) .unwrap_or_else(|| "xmlns".to_owned()),
) namespace.clone(),
.collect(); )
},
))
.collect();
return Ok(Some(Packet::StreamStart(attrs))); return Ok(Some(Packet::StreamStart(attrs)));
} else if self.stanza_builder.depth() == 1 { } else if self.stanza_builder.depth() == 1 {
if let Some(stanza) = self.stanza_builder.unshift_child() { if let Some(stanza) = self.stanza_builder.unshift_child() {