rsm: Split Set into SetQuery and SetResult, and document this.

Emmanuel Gil Peyrot created

Change summary

src/mam.rs |  14 ++--
src/rsm.rs | 176 +++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 130 insertions(+), 60 deletions(-)

Detailed changes

src/mam.rs đź”—

@@ -15,7 +15,7 @@ use error::Error;
 
 use iq::{IqGetPayload, IqSetPayload, IqResultPayload};
 use data_forms::DataForm;
-use rsm::Set;
+use rsm::{SetQuery, SetResult};
 use forwarding::Forwarded;
 use pubsub::NodeName;
 
@@ -42,7 +42,7 @@ generate_element!(
         form: Option<DataForm> = ("x", DATA_FORMS) => DataForm,
 
         /// Used for paging through results.
-        set: Option<Set> = ("set", RSM) => Set
+        set: Option<SetQuery> = ("set", RSM) => SetQuery
     ]
 );
 
@@ -83,11 +83,11 @@ generate_element!(
         /// Describes the current page, it should contain at least [first]
         /// (with an [index]) and [last], and generally [count].
         ///
-        /// [first]: ../rsm/struct.Set.html#structfield.first
-        /// [index]: ../rsm/struct.Set.html#structfield.first_index
-        /// [last]: ../rsm/struct.Set.html#structfield.last
-        /// [count]: ../rsm/struct.Set.html#structfield.count
-        set: Required<Set> = ("set", RSM) => Set
+        /// [first]: ../rsm/struct.SetResult.html#structfield.first
+        /// [index]: ../rsm/struct.SetResult.html#structfield.first_index
+        /// [last]: ../rsm/struct.SetResult.html#structfield.last
+        /// [count]: ../rsm/struct.SetResult.html#structfield.count
+        set: Required<SetResult> = ("set", RSM) => SetResult
     ]
 );
 

src/rsm.rs đź”—

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+#![deny(missing_docs)]
+
 use try_from::TryFrom;
 
 use minidom::Element;
@@ -12,35 +14,42 @@ use error::Error;
 
 use ns;
 
+/// Represents paging through a list of items, represented by an UID.
 #[derive(Debug, Clone)]
-pub struct Set {
+pub struct SetQuery {
+    /// Limit the number of items, or use the recipient’s defaults if None.
+    pub max: Option<usize>,
+
+    /// The UID after which to give results, or if None it is the element
+    /// “before” the first item, effectively an index of negative one.
     pub after: Option<String>,
+
+    /// The UID before which to give results, or if None it starts with the
+    /// last page of the full set.
     pub before: Option<String>,
-    pub count: Option<usize>,
-    pub first: Option<String>,
-    pub first_index: Option<usize>,
+
+    /// Numerical index of the page (deprecated).
     pub index: Option<usize>,
-    pub last: Option<String>,
-    pub max: Option<usize>,
 }
 
-impl TryFrom<Element> for Set {
+impl TryFrom<Element> for SetQuery {
     type Err = Error;
 
-    fn try_from(elem: Element) -> Result<Set, Error> {
+    fn try_from(elem: Element) -> Result<SetQuery, Error> {
         check_self!(elem, "set", RSM, "RSM set");
-        let mut set = Set {
+        let mut set = SetQuery {
+            max: None,
             after: None,
             before: None,
-            count: None,
-            first: None,
-            first_index: None,
             index: None,
-            last: None,
-            max: None,
         };
         for child in elem.children() {
-            if child.is("after", ns::RSM) {
+            if child.is("max", ns::RSM) {
+                if set.max.is_some() {
+                    return Err(Error::ParseError("Set can’t have more than one max."));
+                }
+                set.max = Some(child.text().parse()?);
+            } else if child.is("after", ns::RSM) {
                 if set.after.is_some() {
                     return Err(Error::ParseError("Set can’t have more than one after."));
                 }
@@ -50,32 +59,76 @@ impl TryFrom<Element> for Set {
                     return Err(Error::ParseError("Set can’t have more than one before."));
                 }
                 set.before = Some(child.text());
-            } else if child.is("count", ns::RSM) {
-                if set.count.is_some() {
-                    return Err(Error::ParseError("Set can’t have more than one count."));
+            } else if child.is("index", ns::RSM) {
+                if set.index.is_some() {
+                    return Err(Error::ParseError("Set can’t have more than one index."));
                 }
-                set.count = Some(child.text().parse()?);
-            } else if child.is("first", ns::RSM) {
+                set.index = Some(child.text().parse()?);
+            } else {
+                return Err(Error::ParseError("Unknown child in set element."));
+            }
+        }
+        Ok(set)
+    }
+}
+
+impl From<SetQuery> for Element {
+    fn from(set: SetQuery) -> Element {
+        Element::builder("set")
+                .ns(ns::RSM)
+                .append(set.max.map(|max| Element::builder("max").ns(ns::RSM).append(format!("{}", max)).build()))
+                .append(set.after.map(|after| Element::builder("after").ns(ns::RSM).append(after).build()))
+                .append(set.before.map(|before| Element::builder("before").ns(ns::RSM).append(before).build()))
+                .append(set.index.map(|index| Element::builder("index").ns(ns::RSM).append(format!("{}", index)).build()))
+                .build()
+    }
+}
+
+/// Represents paging through a list of items, represented by an UID.
+#[derive(Debug, Clone)]
+pub struct SetResult {
+    /// The UID of the first item of the page.
+    pub first: Option<String>,
+
+    /// The position of the [first item](#structfield.first) in the full set
+    /// (which may be approximate).
+    pub first_index: Option<usize>,
+
+    /// The UID of the last item of the page.
+    pub last: Option<String>,
+
+    /// How many items there are in the full set (which may be approximate).
+    pub count: Option<usize>,
+}
+
+impl TryFrom<Element> for SetResult {
+    type Err = Error;
+
+    fn try_from(elem: Element) -> Result<SetResult, Error> {
+        check_self!(elem, "set", RSM, "RSM set");
+        let mut set = SetResult {
+            first: None,
+            first_index: None,
+            last: None,
+            count: None,
+        };
+        for child in elem.children() {
+            if child.is("first", ns::RSM) {
                 if set.first.is_some() {
                     return Err(Error::ParseError("Set can’t have more than one first."));
                 }
                 set.first_index = get_attr!(child, "index", optional);
                 set.first = Some(child.text());
-            } else if child.is("index", ns::RSM) {
-                if set.index.is_some() {
-                    return Err(Error::ParseError("Set can’t have more than one index."));
-                }
-                set.index = Some(child.text().parse()?);
             } else if child.is("last", ns::RSM) {
                 if set.last.is_some() {
                     return Err(Error::ParseError("Set can’t have more than one last."));
                 }
                 set.last = Some(child.text());
-            } else if child.is("max", ns::RSM) {
-                if set.max.is_some() {
-                    return Err(Error::ParseError("Set can’t have more than one max."));
+            } else if child.is("count", ns::RSM) {
+                if set.count.is_some() {
+                    return Err(Error::ParseError("Set can’t have more than one count."));
                 }
-                set.max = Some(child.text().parse()?);
+                set.count = Some(child.text().parse()?);
             } else {
                 return Err(Error::ParseError("Unknown child in set element."));
             }
@@ -84,8 +137,8 @@ impl TryFrom<Element> for Set {
     }
 }
 
-impl From<Set> for Element {
-    fn from(set: Set) -> Element {
+impl From<SetResult> for Element {
+    fn from(set: SetResult) -> Element {
         let first = set.first.clone()
                              .map(|first| Element::builder("first")
                                                   .ns(ns::RSM)
@@ -94,13 +147,9 @@ impl From<Set> for Element {
                                                   .build());
         Element::builder("set")
                 .ns(ns::RSM)
-                .append(set.after.map(|after| Element::builder("after").ns(ns::RSM).append(after).build()))
-                .append(set.before.map(|before| Element::builder("before").ns(ns::RSM).append(before).build()))
-                .append(set.count.map(|count| Element::builder("count").ns(ns::RSM).append(format!("{}", count)).build()))
                 .append(first)
-                .append(set.index.map(|index| Element::builder("index").ns(ns::RSM).append(format!("{}", index)).build()))
                 .append(set.last.map(|last| Element::builder("last").ns(ns::RSM).append(last).build()))
-                .append(set.max.map(|max| Element::builder("max").ns(ns::RSM).append(format!("{}", max)).build()))
+                .append(set.count.map(|count| Element::builder("count").ns(ns::RSM).append(format!("{}", count)).build()))
                 .build()
     }
 }
@@ -113,23 +162,34 @@ mod tests {
     #[test]
     fn test_simple() {
         let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
-        let set = Set::try_from(elem).unwrap();
+        let set = SetQuery::try_from(elem).unwrap();
+        assert_eq!(set.max, None);
         assert_eq!(set.after, None);
         assert_eq!(set.before, None);
-        assert_eq!(set.count, None);
+        assert_eq!(set.index, None);
+
+        let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
+        let set = SetResult::try_from(elem).unwrap();
         match set.first {
             Some(_) => panic!(),
             None => (),
         }
-        assert_eq!(set.index, None);
         assert_eq!(set.last, None);
-        assert_eq!(set.max, None);
+        assert_eq!(set.count, None);
     }
 
     #[test]
     fn test_unknown() {
         let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
-        let error = Set::try_from(elem).unwrap_err();
+        let error = SetQuery::try_from(elem).unwrap_err();
+        let message = match error {
+            Error::ParseError(string) => string,
+            _ => panic!(),
+        };
+        assert_eq!(message, "This is not a RSM set element.");
+
+        let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
+        let error = SetResult::try_from(elem).unwrap_err();
         let message = match error {
             Error::ParseError(string) => string,
             _ => panic!(),
@@ -140,7 +200,15 @@ mod tests {
     #[test]
     fn test_invalid_child() {
         let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><coucou/></set>".parse().unwrap();
-        let error = Set::try_from(elem).unwrap_err();
+        let error = SetQuery::try_from(elem).unwrap_err();
+        let message = match error {
+            Error::ParseError(string) => string,
+            _ => panic!(),
+        };
+        assert_eq!(message, "Unknown child in set element.");
+
+        let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><coucou/></set>".parse().unwrap();
+        let error = SetResult::try_from(elem).unwrap_err();
         let message = match error {
             Error::ParseError(string) => string,
             _ => panic!(),
@@ -151,15 +219,21 @@ mod tests {
     #[test]
     fn test_serialise() {
         let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
-        let rsm = Set {
+        let rsm = SetQuery {
+            max: None,
             after: None,
             before: None,
-            count: None,
+            index: None,
+        };
+        let elem2 = rsm.into();
+        assert_eq!(elem, elem2);
+
+        let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
+        let rsm = SetResult {
             first: None,
             first_index: None,
-            index: None,
             last: None,
-            max: None,
+            count: None,
         };
         let elem2 = rsm.into();
         assert_eq!(elem, elem2);
@@ -169,19 +243,15 @@ mod tests {
     fn test_first_index() {
         let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><first index='4'>coucou</first></set>".parse().unwrap();
         let elem1 = elem.clone();
-        let set = Set::try_from(elem).unwrap();
+        let set = SetResult::try_from(elem).unwrap();
         assert_eq!(set.first, Some(String::from("coucou")));
         assert_eq!(set.first_index, Some(4));
 
-        let set2 = Set {
-            after: None,
-            before: None,
-            count: None,
+        let set2 = SetResult {
             first: Some(String::from("coucou")),
             first_index: Some(4),
-            index: None,
             last: None,
-            max: None,
+            count: None,
         };
         let elem2 = set2.into();
         assert!(elem1.compare_to(&elem2));