bind.rs

 1// Copyright (c) 2018 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
 2//
 3// This Source Code Form is subject to the terms of the Mozilla Public
 4// License, v. 2.0. If a copy of the MPL was not distributed with this
 5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
 6
 7use std::str::FromStr;
 8use try_from::TryFrom;
 9
10use minidom::Element;
11
12use error::Error;
13use jid::Jid;
14use ns;
15use iq::{IqSetPayload, IqResultPayload};
16
17#[derive(Debug, Clone, PartialEq)]
18pub enum Bind {
19    None,
20    Resource(String),
21    Jid(Jid),
22}
23
24impl Bind {
25    pub fn new(resource: Option<String>) -> Bind {
26        match resource {
27            None => Bind::None,
28            Some(resource) => Bind::Resource(resource),
29        }
30    }
31}
32
33impl IqSetPayload for Bind {}
34impl IqResultPayload for Bind {}
35
36impl TryFrom<Element> for Bind {
37    type Err = Error;
38
39    fn try_from(elem: Element) -> Result<Bind, Error> {
40        check_self!(elem, "bind", BIND);
41        check_no_attributes!(elem, "bind");
42
43        let mut bind = Bind::None;
44        for child in elem.children() {
45            if bind != Bind::None {
46                return Err(Error::ParseError("Bind can only have one child."));
47            }
48            if child.is("resource", ns::BIND) {
49                check_no_children!(child, "resource");
50                bind = Bind::Resource(child.text());
51            } else if child.is("jid", ns::BIND) {
52                check_no_children!(child, "jid");
53                bind = Bind::Jid(Jid::from_str(&child.text())?);
54            } else {
55                return Err(Error::ParseError("Unknown element in bind."));
56            }
57        }
58
59        Ok(bind)
60    }
61}
62
63impl From<Bind> for Element {
64    fn from(bind: Bind) -> Element {
65        Element::builder("bind")
66                .ns(ns::BIND)
67                .append(match bind {
68                     Bind::None => vec!(),
69                     Bind::Resource(resource) => vec!(
70                         Element::builder("resource")
71                                 .ns(ns::BIND)
72                                 .append(resource)
73                                 .build()
74                     ),
75                     Bind::Jid(jid) => vec!(
76                         Element::builder("jid")
77                                 .ns(ns::BIND)
78                                 .append(jid)
79                                 .build()
80                     ),
81                 })
82                .build()
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_simple() {
92        let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>".parse().unwrap();
93        let bind = Bind::try_from(elem).unwrap();
94        assert_eq!(bind, Bind::None);
95    }
96}