@@ -25,42 +25,27 @@ generate_element_with_only_attributes!(Open, "open", ns::IBB, [
stanza: Stanza = "stanza" => default,
]);
-#[derive(Debug, Clone)]
-pub struct Data {
- pub seq: u16,
- pub sid: String,
- pub data: Vec<u8>,
-}
+/// Codec wrapping base64 encode/decode
+struct Base64;
-impl TryFrom<Element> for Data {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Data, Error> {
- if !elem.is("data", ns::IBB) {
- return Err(Error::ParseError("This is not a data element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in data element."));
- }
- Ok(Data {
- seq: get_attr!(elem, "seq", required),
- sid: get_attr!(elem, "sid", required),
- data: base64::decode(&elem.text())?,
- })
+impl Base64 {
+ fn decode(s: &str) -> Result<Vec<u8>, Error> {
+ Ok(base64::decode(s)?)
}
-}
-impl From<Data> for Element {
- fn from(data: Data) -> Element {
- Element::builder("data")
- .ns(ns::IBB)
- .attr("seq", data.seq)
- .attr("sid", data.sid)
- .append(base64::encode(&data.data))
- .build()
+ fn encode(b: &Vec<u8>) -> String {
+ base64::encode(b)
}
}
+generate_element_with_text!(Data, "data", ns::IBB,
+ [
+ seq: u16 = "seq" => required,
+ sid: String = "sid" => required
+ ],
+ data: Base64<Vec<u8>>
+);
+
generate_element_with_only_attributes!(Close, "close", ns::IBB, [
sid: String = "sid" => required,
]);
@@ -251,3 +251,45 @@ macro_rules! generate_elem_id {
}
);
}
+
+macro_rules! generate_element_with_text {
+ ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+], $text_ident:ident: $codec:ident < $text_type:ty >) => (
+ $(#[$meta])*
+ #[derive(Debug, Clone)]
+ pub struct $elem {
+ $(
+ $(#[$attr_meta])*
+ pub $attr: $attr_type
+ ),*,
+ pub $text_ident: $text_type,
+ }
+
+ impl TryFrom<Element> for $elem {
+ type Err = Error;
+
+ fn try_from(elem: Element) -> Result<$elem, Error> {
+ check_self!(elem, $name, $ns);
+ check_no_children!(elem, $name);
+ check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
+ Ok($elem {
+ $(
+ $attr: get_attr!(elem, $attr_name, $attr_action)
+ ),*,
+ $text_ident: $codec::decode(&elem.text())?,
+ })
+ }
+ }
+
+ impl From<$elem> for Element {
+ fn from(elem: $elem) -> Element {
+ Element::builder($name)
+ .ns($ns)
+ $(
+ .attr($attr_name, elem.$attr)
+ )*
+ .append($codec::encode(&elem.$text_ident))
+ .build()
+ }
+ }
+ );
+}