xmpp-parsers: Convert vCard-temp to xso

Emmanuel Gil Peyrot created

This also keeps all additional elements in the vCard, so they get
serialized back on the wire instead of being dropped.

Change summary

parsers/ChangeLog    |  4 +++
parsers/src/vcard.rs | 54 ++++++++++++++++++++-------------------------
2 files changed, 28 insertions(+), 30 deletions(-)

Detailed changes

parsers/ChangeLog 🔗

@@ -28,6 +28,10 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
       - The bookmarks2 Conference `extensions` child is now an
         `Option<Extensions>` instead of a `Vec<Element>`, to distinguish
         between it being absent or empty (!472).
+    * Improvements:
+      - Keep unsupported vCard elements as `minidom::Element`, so that they
+        get serialized back instead of being dropped.  We now also test for
+        the size of these elements (!472).
     * New parsers/serialisers:
         - Stream Features (RFC 6120) (!400)
         - Extensible SASL Profile (XEP-0388)

parsers/src/vcard.rs 🔗

@@ -14,7 +14,6 @@
 //! see [`vcard_update`][crate::vcard_update] module.
 
 use xso::{
-    error::Error,
     text::{Base64, StripWhitespace, TextCodec},
     AsXml, FromXml,
 };
@@ -55,39 +54,16 @@ pub struct Binval {
 }
 
 /// A `<vCard>` element; only the `<PHOTO>` element is supported for this legacy vCard ; the rest is ignored.
+#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
+#[xml(namespace = ns::VCARD, name = "vCard")]
 pub struct VCard {
     /// A photo element.
+    #[xml(child(default))]
     pub photo: Option<Photo>,
-}
-
-impl TryFrom<Element> for VCard {
-    type Error = xso::error::Error;
-
-    fn try_from(value: Element) -> Result<Self, Self::Error> {
-        // Check that the root element is <vCard>
-        if !value.is("vCard", ns::VCARD) {
-            return Err(Error::Other(
-                "Root element is not <vCard xmlns='vcard-temp'>",
-            ));
-        }
-
-        // Parse the <PHOTO> element, if any.
-        let photo = value
-            .get_child("PHOTO", ns::VCARD)
-            .map(|photo| Photo::try_from(photo.clone()))
-            .transpose()?;
-
-        // Return the result.
-        Ok(VCard { photo })
-    }
-}
 
-impl From<VCard> for Element {
-    fn from(vcard: VCard) -> Element {
-        Element::builder("vCard", ns::VCARD)
-            .append_all(vcard.photo)
-            .build()
-    }
+    /// Every other element in the vCard.
+    #[xml(element(n = ..))]
+    pub payloads: Vec<Element>,
 }
 
 impl IqGetPayload for VCard {}
@@ -100,6 +76,24 @@ mod tests {
     use base64::Engine;
     use std::str::FromStr;
 
+    #[cfg(target_pointer_width = "32")]
+    #[test]
+    fn test_size() {
+        assert_size!(Photo, 24);
+        assert_size!(Type, 12);
+        assert_size!(Binval, 12);
+        assert_size!(VCard, 36);
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[test]
+    fn test_size() {
+        assert_size!(Photo, 48);
+        assert_size!(Type, 24);
+        assert_size!(Binval, 24);
+        assert_size!(VCard, 72);
+    }
+
     #[test]
     fn test_vcard() {
         // Create some bytes: