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;
15
16#[derive(Debug, Clone, PartialEq)]
17pub enum Bind {
18    None,
19    Resource(String),
20    Jid(Jid),
21}
22
23impl Bind {
24    pub fn new(resource: Option<String>) -> Bind {
25        match resource {
26            None => Bind::None,
27            Some(resource) => Bind::Resource(resource),
28        }
29    }
30}
31
32impl TryFrom<Element> for Bind {
33    type Err = Error;
34
35    fn try_from(elem: Element) -> Result<Bind, Error> {
36        check_self!(elem, "bind", ns::BIND);
37        check_no_attributes!(elem, "bind");
38
39        let mut bind = Bind::None;
40        for child in elem.children() {
41            if bind != Bind::None {
42                return Err(Error::ParseError("Bind can only have one child."));
43            }
44            if child.is("resource", ns::BIND) {
45                check_no_children!(child, "resource");
46                bind = Bind::Resource(child.text());
47            } else if child.is("jid", ns::BIND) {
48                check_no_children!(child, "jid");
49                bind = Bind::Jid(Jid::from_str(&child.text())?);
50            } else {
51                return Err(Error::ParseError("Unknown element in bind."));
52            }
53        }
54
55        Ok(bind)
56    }
57}
58
59impl From<Bind> for Element {
60    fn from(bind: Bind) -> Element {
61        Element::builder("bind")
62                .ns(ns::BIND)
63                .append(match bind {
64                     Bind::None => vec!(),
65                     Bind::Resource(resource) => vec!(
66                         Element::builder("resource")
67                                 .ns(ns::BIND)
68                                 .append(resource)
69                                 .build()
70                     ),
71                     Bind::Jid(jid) => vec!(
72                         Element::builder("jid")
73                                 .ns(ns::BIND)
74                                 .append(jid)
75                                 .build()
76                     ),
77                 })
78                .build()
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_simple() {
88        let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>".parse().unwrap();
89        let bind = Bind::try_from(elem).unwrap();
90        assert_eq!(bind, Bind::None);
91    }
92}