Repository: z-galaxy/zbus (Rust)

Issue:
org.freedesktop.zbus.Error: invalid length 19, expected >= 20
We are getting message like these when zvariant 5.4 and 5.5 are communicating with each other. I don't know for sure, but I could imagine that the following byte difference is causing the issue.

```
fn main() {
    let ctxt = zvariant::serialized::Context::new_dbus(zvariant::LE, 0);
    let data = zvariant::to_bytes(ctxt, &X::default()).unwrap();

    println!("{:?}", data.bytes());
    // zvariant 5.4.0 output:
    // [0, 0, 0, 0, 0, 0, 0, 0]

    // zvariant 5.5.1, 5.5.2, 5.5.3 output:
    // [0]
}

#[derive(zvariant::DeserializeDict, zvariant::SerializeDict, zvariant::Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct X {
    pub scale: Option<u32>,
}
```


Discussion:
Related: https://gitlab.gnome.org/GNOME/snapshot/-/merge_requests/382
Ouch! Looks like a regression in 5.5 since the 5.4 output looks correct (the ARRAY's len header of 4 bytes + 4 bytes of padding for the first element, which if of type DICT_ENTRY). I'll take a look soon..



Patch:
diff --git a/zvariant/src/dbus/ser.rs b/zvariant/src/dbus/ser.rs
index 5fa765dc8..08cf25276 100644
--- a/zvariant/src/dbus/ser.rs
+++ b/zvariant/src/dbus/ser.rs
@@ -326,22 +326,19 @@ where
     }
 
     fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
-        if len == 0 {
-            return StructSerializer::unit(self).map(StructSeqSerializer::Struct);
-        }
-
         self.0
             .add_padding(self.0.signature.alignment(self.0.ctxt.format()))?;
         match &self.0.signature {
             Signature::Variant => StructSerializer::variant(self).map(StructSeqSerializer::Struct),
             Signature::Array(_) => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq),
+            Signature::U8 => StructSerializer::unit(self).map(StructSeqSerializer::Struct),
             Signature::Structure(_) => {
                 StructSerializer::structure(self).map(StructSeqSerializer::Struct)
             }
             Signature::Dict { .. } => self.serialize_map(Some(len)).map(StructSeqSerializer::Map),
             _ => Err(Error::SignatureMismatch(
                 self.0.signature.clone(),
-                "a struct, array or variant".to_string(),
+                "a struct, array, u8 or variant".to_string(),
             )),
         }
     }
diff --git a/zvariant/src/gvariant/ser.rs b/zvariant/src/gvariant/ser.rs
index fbff0a601..86746c55f 100644
--- a/zvariant/src/gvariant/ser.rs
+++ b/zvariant/src/gvariant/ser.rs
@@ -327,15 +327,12 @@ where
     }
 
     fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
-        if len == 0 {
-            return StructSerializer::unit(self).map(StructSeqSerializer::Struct);
-        }
-
         self.0
             .add_padding(self.0.signature.alignment(self.0.ctxt.format()))?;
         match &self.0.signature {
             Signature::Variant => StructSerializer::variant(self).map(StructSeqSerializer::Struct),
             Signature::Array(_) => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq),
+            Signature::U8 => StructSerializer::unit(self).map(StructSeqSerializer::Struct),
             Signature::Structure(_) => {
                 StructSerializer::structure(self).map(StructSeqSerializer::Struct)
             }
@@ -343,7 +340,7 @@ where
             _ => {
                 return Err(Error::SignatureMismatch(
                     self.0.signature.clone(),
-                    "a struct, array or variant".to_string(),
+                    "a struct, array, u8 or variant".to_string(),
                 ));
             }
         }


Test patch:
diff --git a/zvariant/tests/dict_value.rs b/zvariant/tests/dict_value.rs
index 227393d2a..fdbfcf6d4 100644
--- a/zvariant/tests/dict_value.rs
+++ b/zvariant/tests/dict_value.rs
@@ -235,4 +235,10 @@ fn dict_value() {
     #[derive(Default, Debug, SerializeDict, DeserializeDict, Type)]
     #[zvariant(signature = "dict")]
     struct TestEmpty {}
+
+    // Empty dict should be serialized to contain 4 bytes for the ARRAY length and 4 bytes for the
+    // DICT_ENTRY alignment to 8 bytes boundary.
+    let data = to_bytes(ctxt, &TestEmpty::default()).unwrap();
+
+    assert_eq!(data.bytes(), &[0, 0, 0, 0, 0, 0, 0, 0]);
 }