diff --git a/src/ibb.rs b/src/ibb.rs index 7d7f3e73fa501e4a7ffd63e1586bac52ba8532ee..cc2d89c3c11fba3eb704ee87da6ed11c674a5f76 100644 --- a/src/ibb.rs +++ b/src/ibb.rs @@ -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, -} +/// Codec wrapping base64 encode/decode +struct Base64; -impl TryFrom for Data { - type Err = Error; - - fn try_from(elem: Element) -> Result { - 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, Error> { + Ok(base64::decode(s)?) } -} -impl From 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) -> String { + base64::encode(b) } } +generate_element_with_text!(Data, "data", ns::IBB, + [ + seq: u16 = "seq" => required, + sid: String = "sid" => required + ], + data: Base64> +); + generate_element_with_only_attributes!(Close, "close", ns::IBB, [ sid: String = "sid" => required, ]); diff --git a/src/macros.rs b/src/macros.rs index 97f0adcdc684aa774aac7dedd433e739d766d40f..155767ac0bb5b5169bae421d31426a1c61c553f5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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 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() + } + } + ); +}