message: Enforce more type safety on Body, Subject and Thread.

This commit is contained in:
Emmanuel Gil Peyrot 2017-07-29 06:11:48 +01:00
parent 6ec1e46953
commit 56a66f8c4b

View file

@ -115,9 +115,10 @@ generate_attribute!(MessageType, "type", {
}, Default = Normal); }, Default = Normal);
type Lang = String; type Lang = String;
type Body = String;
type Subject = String; generate_elem_id!(Body, "body", ns::JABBER_CLIENT);
type Thread = String; generate_elem_id!(Subject, "subject", ns::JABBER_CLIENT);
generate_elem_id!(Thread, "thread", ns::JABBER_CLIENT);
/// The main structure representing the `<message/>` stanza. /// The main structure representing the `<message/>` stanza.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -168,7 +169,8 @@ impl TryFrom<Element> for Message {
return Err(Error::ParseError("Unknown child in body element.")); return Err(Error::ParseError("Unknown child in body element."));
} }
let lang = get_attr!(root, "xml:lang", default); let lang = get_attr!(root, "xml:lang", default);
if bodies.insert(lang, elem.text()).is_some() { let body = Body(elem.text());
if bodies.insert(lang, body).is_some() {
return Err(Error::ParseError("Body element present twice for the same xml:lang.")); return Err(Error::ParseError("Body element present twice for the same xml:lang."));
} }
} else if elem.is("subject", ns::JABBER_CLIENT) { } else if elem.is("subject", ns::JABBER_CLIENT) {
@ -176,7 +178,8 @@ impl TryFrom<Element> for Message {
return Err(Error::ParseError("Unknown child in subject element.")); return Err(Error::ParseError("Unknown child in subject element."));
} }
let lang = get_attr!(root, "xml:lang", default); let lang = get_attr!(root, "xml:lang", default);
if subjects.insert(lang, elem.text()).is_some() { let subject = Subject(elem.text());
if subjects.insert(lang, subject).is_some() {
return Err(Error::ParseError("Subject element present twice for the same xml:lang.")); return Err(Error::ParseError("Subject element present twice for the same xml:lang."));
} }
} else if elem.is("thread", ns::JABBER_CLIENT) { } else if elem.is("thread", ns::JABBER_CLIENT) {
@ -186,7 +189,7 @@ impl TryFrom<Element> for Message {
for _ in elem.children() { for _ in elem.children() {
return Err(Error::ParseError("Unknown child in thread element.")); return Err(Error::ParseError("Unknown child in thread element."));
} }
thread = Some(elem.text()); thread = Some(Thread(elem.text()));
} else { } else {
payloads.push(elem.clone()) payloads.push(elem.clone())
} }
@ -214,25 +217,23 @@ impl From<Message> for Element {
.attr("type", message.type_) .attr("type", message.type_)
.append(message.subjects.into_iter() .append(message.subjects.into_iter()
.map(|(lang, subject)| { .map(|(lang, subject)| {
Element::builder("subject") let mut subject = Element::from(subject);
.ns(ns::JABBER_CLIENT) subject.set_attr("xml:lang", match lang.as_ref() {
.attr("xml:lang", match lang.as_ref() { "" => None,
"" => None, lang => Some(lang),
lang => Some(lang), });
}) subject
.append(subject) })
.build() })
.collect::<Vec<_>>()) .collect::<Vec<_>>())
.append(message.bodies.into_iter() .append(message.bodies.into_iter()
.map(|(lang, body)| { .map(|(lang, body)| {
Element::builder("body") let mut body = Element::from(body);
.ns(ns::JABBER_CLIENT) body.set_attr("xml:lang", match lang.as_ref() {
.attr("xml:lang", match lang.as_ref() { "" => None,
"" => None, lang => Some(lang),
lang => Some(lang), });
}) body
.append(body) })
.build() })
.collect::<Vec<_>>()) .collect::<Vec<_>>())
.append(message.payloads) .append(message.payloads)
.build() .build()
@ -268,7 +269,7 @@ mod tests {
let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap(); let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
let elem1 = elem.clone(); let elem1 = elem.clone();
let message = Message::try_from(elem).unwrap(); let message = Message::try_from(elem).unwrap();
assert_eq!(message.bodies[""], "Hello world!"); assert_eq!(message.bodies[""], Body::from_str("Hello world!").unwrap());
let elem2 = message.into(); let elem2 = message.into();
assert_eq!(elem1, elem2); assert_eq!(elem1, elem2);
@ -278,7 +279,7 @@ mod tests {
fn test_serialise_body() { fn test_serialise_body() {
let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap(); let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
let mut message = Message::new(Some(Jid::from_str("coucou@example.org").unwrap())); let mut message = Message::new(Some(Jid::from_str("coucou@example.org").unwrap()));
message.bodies.insert(String::from(""), String::from("Hello world!")); message.bodies.insert(String::from(""), Body::from_str("Hello world!").unwrap());
let elem2 = message.into(); let elem2 = message.into();
assert_eq!(elem, elem2); assert_eq!(elem, elem2);
} }
@ -288,7 +289,7 @@ mod tests {
let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><subject>Hello world!</subject></message>".parse().unwrap(); let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><subject>Hello world!</subject></message>".parse().unwrap();
let elem1 = elem.clone(); let elem1 = elem.clone();
let message = Message::try_from(elem).unwrap(); let message = Message::try_from(elem).unwrap();
assert_eq!(message.subjects[""], "Hello world!"); assert_eq!(message.subjects[""], Subject::from_str("Hello world!").unwrap());
let elem2 = message.into(); let elem2 = message.into();
assert_eq!(elem1, elem2); assert_eq!(elem1, elem2);