From b5de6cb82c56c8c2c95c5806584befdc756edb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?= Date: Sat, 30 Mar 2024 10:03:49 +0100 Subject: [PATCH] xmpp_parsers::jingle: add ReasonElement::other MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Jingle XEP states [1] that the `` element may contain up to one element which further qualifies the error condition: > The element MAY contain an element qualified by some other > namespace that provides more detailed machine-readable information > about the reason for the action. The schema agrees: > ``` > > > > > > > > > > ``` [1]: https://xmpp.org/extensions/xep-0166.html#def-reason --- parsers/src/jingle.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/parsers/src/jingle.rs b/parsers/src/jingle.rs index eb2ea9e..84e704d 100644 --- a/parsers/src/jingle.rs +++ b/parsers/src/jingle.rs @@ -468,6 +468,11 @@ pub struct ReasonElement { /// A human-readable description of this reason. pub text: Option, + + /// A machine-readable extension of the reason. + // using a box here to save a significant amount of bytes in the common + // (absent) case. + pub other: Option>, } impl fmt::Display for ReasonElement { @@ -488,6 +493,7 @@ impl TryFrom for ReasonElement { check_no_attributes!(elem, "reason"); let mut reason = None; let mut text = None; + let mut other = None; for child in elem.children() { if child.is("text", ns::JINGLE) { check_no_children!(child, "text"); @@ -505,12 +511,18 @@ impl TryFrom for ReasonElement { check_no_children!(child, "reason"); check_no_attributes!(child, "reason"); reason = Some(child.name().parse()?); + } else if other.is_none() { + other = Some(Box::new(child.clone())); } else { return Err(Error::ParseError("Reason contains a foreign element.")); } } let reason = reason.ok_or(Error::ParseError("Reason doesn’t contain a valid reason."))?; - Ok(ReasonElement { reason, text }) + Ok(ReasonElement { + reason, + text, + other, + }) } } @@ -524,6 +536,7 @@ impl From for Element { .into_iter() .map(|text| Element::builder("text", ns::JINGLE).append(text)), ) + .append_all(reason.other.into_iter().map(|other| *other)) .build() } } @@ -684,9 +697,9 @@ mod tests { assert_size!(ContentId, 12); assert_size!(Content, 216); assert_size!(Reason, 1); - assert_size!(ReasonElement, 16); + assert_size!(ReasonElement, 20); assert_size!(SessionId, 12); - assert_size!(Jingle, 104); + assert_size!(Jingle, 108); } #[cfg(target_pointer_width = "64")] @@ -703,9 +716,9 @@ mod tests { #[cfg(feature = "stable")] assert_size!(Content, 440); assert_size!(Reason, 1); - assert_size!(ReasonElement, 32); + assert_size!(ReasonElement, 40); assert_size!(SessionId, 24); - assert_size!(Jingle, 208); + assert_size!(Jingle, 216); } #[test] @@ -850,7 +863,7 @@ mod tests { Error::ParseError(string) => string, _ => panic!(), }; - assert_eq!(message, "Reason contains a foreign element."); + assert_eq!(message, "Reason doesn’t contain a valid reason."); let elem: Element = "".parse().unwrap(); let error = Jingle::try_from(elem).unwrap_err();