dbus2 / zbus-old

Rust D-Bus crate.
https://gitlab.freedesktop.org/dbus/zbus
Other
49 stars 13 forks source link

Nested Dict types 'a{sa{sv}}' are not supported #322

Open zeenix opened 1 year ago

zeenix commented 1 year ago

In GitLab by @seiwill on Feb 1, 2023, 17:58

Dictionary of Dictionaries is not supported and returns an Error::PaddingNot0 when decoded by Message::body().

This code attempts to get the ActiveConnection Settings from NetworkManager. It reads the a{sa{sv}} ConnectionSettings which Optionally contains other Dict Structs.

use zbus::{blocking::{Connection, Proxy}, zvariant::{DeserializeDict, Type, OwnedObjectPath}};

#[derive(Debug, Clone, PartialEq, Default, Type, DeserializeDict)]
#[zvariant(signature = "dict")]
pub struct SettingsConnection {
    pub autoconnect: Option<bool>,
    pub id: Option<String>,
    pub interface_name: Option<String>,
    pub read_only: Option<bool>,
    pub timestamp: Option<u64>,
    #[zvariant(rename = "type")]
    pub connection_type: Option<String>,
    pub uuid: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Default, Type, DeserializeDict)]
#[zvariant(signature = "dict")]
pub struct SettingsIp {
    pub method: Option<String>,
    pub addresses: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Default, Type, DeserializeDict)]
#[zvariant(signature = "a{sa{sv}}")]
pub struct ConnectionSettings {
    pub connection: Option<SettingsConnection>,
    pub ipv4: Option<SettingsIp>,
}

fn main() {
    let connection = Connection::system().unwrap();
    let proxy = Proxy::new(
        &connection,
        "org.freedesktop.NetworkManager",
        "/org/freedesktop/NetworkManager",
        "org.freedesktop.NetworkManager"
    ).unwrap();

    let active_connections: Vec<OwnedObjectPath> = proxy.get_property("ActiveConnections").unwrap();
    for ac in active_connections {
        println!("Looking up {ac:?}");

        let ac_proxy = Proxy::new(
            &connection,
            "org.freedesktop.NetworkManager",
            &ac,
            "org.freedesktop.NetworkManager.Connection.Active"
        ).unwrap();
        let conn_path: OwnedObjectPath = ac_proxy.get_property("Connection").unwrap();
        println!("  Connection Settings {conn_path:?}");

        let settings_proxy = Proxy::new(
            &connection,
            "org.freedesktop.NetworkManager",
            &conn_path,
            "org.freedesktop.NetworkManager.Settings.Connection"
        ).unwrap();

        let message = settings_proxy.call_method("GetSettings", &()).unwrap();
        println!("  Reply: {message:?}");

        // let settings_map : HashMap<String, HashMap<String, zvariant::OwnedValue>> = message.body().unwrap();
        let settings = message.body::<ConnectionSettings>().unwrap();
        println!("  {settings:?}\n");
    }
}

Running panics on the message.body().unwrap():

Looking up OwnedObjectPath(ObjectPath("/org/freedesktop/NetworkManager/ActiveConnection/5"))
  Connection Settings OwnedObjectPath(ObjectPath("/org/freedesktop/NetworkManager/Settings/23"))
  Reply: Msg { type: MethodReturn, sender: UniqueName(Str(Borrowed(":1.5"))), reply-serial: 13, body: Signature("a{sa{sv}}") }
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Variant(PaddingNot0(15))', src/main.rs:102:61
stack backtrace:
   0: rust_begin_unwind
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/panicking.rs:142:14
   2: core::result::unwrap_failed
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/result.rs:1814:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/result.rs:1107:23
   4: nm_test::main
             at ./src/main.rs:102:24
   5: core::ops::function::FnOnce::call_once
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/ops/function.rs:248:5