1// Copyright (c) 2017 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::convert::TryFrom;
8
9use minidom::Element;
10
11use error::Error;
12
13use ns;
14
15#[derive(Debug, Clone)]
16pub struct Set {
17 pub after: Option<String>,
18 pub before: Option<String>,
19 pub count: Option<usize>,
20 pub first: Option<String>,
21 pub first_index: Option<usize>,
22 pub index: Option<usize>,
23 pub last: Option<String>,
24 pub max: Option<usize>,
25}
26
27impl TryFrom<Element> for Set {
28 type Error = Error;
29
30 fn try_from(elem: Element) -> Result<Set, Error> {
31 if !elem.is("set", ns::RSM) {
32 return Err(Error::ParseError("This is not a RSM element."));
33 }
34 let mut set = Set {
35 after: None,
36 before: None,
37 count: None,
38 first: None,
39 first_index: None,
40 index: None,
41 last: None,
42 max: None,
43 };
44 for child in elem.children() {
45 if child.is("after", ns::RSM) {
46 if set.after.is_some() {
47 return Err(Error::ParseError("Set can’t have more than one after."));
48 }
49 set.after = Some(child.text());
50 } else if child.is("before", ns::RSM) {
51 if set.before.is_some() {
52 return Err(Error::ParseError("Set can’t have more than one before."));
53 }
54 set.before = Some(child.text());
55 } else if child.is("count", ns::RSM) {
56 if set.count.is_some() {
57 return Err(Error::ParseError("Set can’t have more than one count."));
58 }
59 set.count = Some(child.text().parse()?);
60 } else if child.is("first", ns::RSM) {
61 if set.first.is_some() {
62 return Err(Error::ParseError("Set can’t have more than one first."));
63 }
64 set.first_index = get_attr!(child, "index", optional);
65 set.first = Some(child.text());
66 } else if child.is("index", ns::RSM) {
67 if set.index.is_some() {
68 return Err(Error::ParseError("Set can’t have more than one index."));
69 }
70 set.index = Some(child.text().parse()?);
71 } else if child.is("last", ns::RSM) {
72 if set.last.is_some() {
73 return Err(Error::ParseError("Set can’t have more than one last."));
74 }
75 set.last = Some(child.text());
76 } else if child.is("max", ns::RSM) {
77 if set.max.is_some() {
78 return Err(Error::ParseError("Set can’t have more than one max."));
79 }
80 set.max = Some(child.text().parse()?);
81 } else {
82 return Err(Error::ParseError("Unknown child in set element."));
83 }
84 }
85 Ok(set)
86 }
87}
88
89impl Into<Element> for Set {
90 fn into(self) -> Element {
91 let mut elem = Element::builder("set")
92 .ns(ns::RSM)
93 .build();
94 if self.after.is_some() {
95 elem.append_child(Element::builder("after").ns(ns::RSM).append(self.after).build());
96 }
97 if self.before.is_some() {
98 elem.append_child(Element::builder("before").ns(ns::RSM).append(self.before).build());
99 }
100 if self.count.is_some() {
101 elem.append_child(Element::builder("count").ns(ns::RSM).append(format!("{}", self.count.unwrap())).build());
102 }
103 if self.first.is_some() {
104 elem.append_child(Element::builder("first")
105 .ns(ns::RSM)
106 .attr("index", self.first_index.map(|index| format!("{}", index)))
107 .append(self.first).build());
108 }
109 if self.index.is_some() {
110 elem.append_child(Element::builder("index").ns(ns::RSM).append(format!("{}", self.index.unwrap())).build());
111 }
112 if self.last.is_some() {
113 elem.append_child(Element::builder("last").ns(ns::RSM).append(self.last).build());
114 }
115 if self.max.is_some() {
116 elem.append_child(Element::builder("max").ns(ns::RSM).append(format!("{}", self.max.unwrap())).build());
117 }
118 elem
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_simple() {
128 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
129 let set = Set::try_from(elem).unwrap();
130 assert_eq!(set.after, None);
131 assert_eq!(set.before, None);
132 assert_eq!(set.count, None);
133 match set.first {
134 Some(_) => panic!(),
135 None => (),
136 }
137 assert_eq!(set.index, None);
138 assert_eq!(set.last, None);
139 assert_eq!(set.max, None);
140 }
141
142 #[test]
143 fn test_unknown() {
144 let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
145 let error = Set::try_from(elem).unwrap_err();
146 let message = match error {
147 Error::ParseError(string) => string,
148 _ => panic!(),
149 };
150 assert_eq!(message, "This is not a RSM element.");
151 }
152
153 #[test]
154 fn test_invalid_child() {
155 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><coucou/></set>".parse().unwrap();
156 let error = Set::try_from(elem).unwrap_err();
157 let message = match error {
158 Error::ParseError(string) => string,
159 _ => panic!(),
160 };
161 assert_eq!(message, "Unknown child in set element.");
162 }
163
164 #[test]
165 fn test_serialise() {
166 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
167 let rsm = Set {
168 after: None,
169 before: None,
170 count: None,
171 first: None,
172 first_index: None,
173 index: None,
174 last: None,
175 max: None,
176 };
177 let elem2 = rsm.into();
178 assert_eq!(elem, elem2);
179 }
180
181 #[test]
182 fn test_first_index() {
183 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><first index='4'>coucou</first></set>".parse().unwrap();
184 let elem1 = elem.clone();
185 let set = Set::try_from(elem).unwrap();
186 assert_eq!(set.first, Some(String::from("coucou")));
187 assert_eq!(set.first_index, Some(4));
188
189 let set2 = Set {
190 after: None,
191 before: None,
192 count: None,
193 first: Some(String::from("coucou")),
194 first_index: Some(4),
195 index: None,
196 last: None,
197 max: None,
198 };
199 let elem2 = set2.into();
200 assert_eq!(elem1, elem2);
201 }
202}