diff --git a/src/mam.rs b/src/mam.rs index 68d4f104..efc62135 100644 --- a/src/mam.rs +++ b/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 = ("x", DATA_FORMS) => DataForm, /// Used for paging through results. - set: Option = ("set", RSM) => Set + set: Option = ("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", 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 = ("set", RSM) => SetResult ] ); diff --git a/src/rsm.rs b/src/rsm.rs index 74484e85..2aeeedd7 100644 --- a/src/rsm.rs +++ b/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 after: Option, - pub before: Option, - pub count: Option, - pub first: Option, - pub first_index: Option, - pub index: Option, - pub last: Option, +pub struct SetQuery { + /// Limit the number of items, or use the recipient’s defaults if None. pub max: Option, + + /// 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, + + /// The UID before which to give results, or if None it starts with the + /// last page of the full set. + pub before: Option, + + /// Numerical index of the page (deprecated). + pub index: Option, } -impl TryFrom for Set { +impl TryFrom for SetQuery { type Err = Error; - fn try_from(elem: Element) -> Result { + fn try_from(elem: Element) -> Result { 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,11 @@ impl TryFrom 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.")); - } - set.count = Some(child.text().parse()?); - } else 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.")); - } - set.max = Some(child.text().parse()?); } else { return Err(Error::ParseError("Unknown child in set element.")); } @@ -84,8 +72,73 @@ impl TryFrom for Set { } } -impl From for Element { - fn from(set: Set) -> Element { +impl From 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, + + /// The position of the [first item](#structfield.first) in the full set + /// (which may be approximate). + pub first_index: Option, + + /// The UID of the last item of the page. + pub last: Option, + + /// How many items there are in the full set (which may be approximate). + pub count: Option, +} + +impl TryFrom for SetResult { + type Err = Error; + + fn try_from(elem: Element) -> Result { + 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("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("count", ns::RSM) { + if set.count.is_some() { + return Err(Error::ParseError("Set can’t have more than one count.")); + } + set.count = Some(child.text().parse()?); + } else { + return Err(Error::ParseError("Unknown child in set element.")); + } + } + Ok(set) + } +} + +impl From 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 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 = "".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 = "".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 = "".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 = "".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 = "".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 = "".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 = "".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 = "".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 = "coucou".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));