使用 Rust DBUS 库时,不满足 trait bound `dbus::arg::Get`

Posted

技术标签:

【中文标题】使用 Rust DBUS 库时,不满足 trait bound `dbus::arg::Get`【英文标题】:The trait bound `dbus::arg::Get` is not satisfied when using the Rust DBUS library 【发布时间】:2017-05-17 12:00:07 【问题描述】:

我正在尝试使用 the dbus-rs 库通过 GetSettings 方法从 NetworkManager 获取连接信息。我用D-Feet试了一下签名为GetSettings() -> (Dict of String, Dict of String, Variant settings)的函数,D-Feet返回的数据如下:

'802-11-wireless': 'mac-address': [228, 179, 24, 77, 64, 139],
                     'mac-address-blacklist': [],
                     'mode': 'infrastructure',
                     'security': '802-11-wireless-security',
                     'seen-bssids': ['02:1D:AA:80:1B:DA', '02:1D:AA:80:1D:12'],
                     'ssid': [80,
                              108,
                              111,
                              117,
                              103,
                              104,
                              32,
                              87,
                              97,
                              121,
                              32,
                              67,
                              97,
                              102,
                              101],
 '802-11-wireless-security': 'auth-alg': 'open',
                              'group': [],
                              'key-mgmt': 'wpa-psk',
                              'pairwise': [],
                              'proto': [],
 'connection': 'id': 'Plough Way Cafe',
                'permissions': [],
                'secondaries': [],
                'timestamp': 1479304123,
                'type': '802-11-wireless',
                'uuid': 'ff9b7028-0911-491a-bfe8-53cba76069da',
 'ipv4': 'address-data': [],
          'addresses': [],
          'dns': [],
          'dns-search': [],
          'method': 'auto',
          'route-data': [],
          'routes': [],
 'ipv6': 'address-data': [],
          'addresses': [],
          'dns': [],
          'dns-search': [],
          'method': 'auto',
          'route-data': [],
          'routes': []

和我的代码:

extern crate dbus;

fn main() 
    let message = dbus::Message::new_method_call("org.freedesktop.NetworkManager",
                                                 "/org/freedesktop/NetworkManager/Settings/0",
                                                 "org.freedesktop.NetworkManager.Settings.\
                                                  Connection",
                                                 "GetSettings")
        .unwrap();

    let response = dbus::Connection::get_private(dbus::BusType::System)
        .unwrap()
        .send_with_reply_and_block(message, 2000)
        .unwrap();

    println!(":?", response);

    let test: dbus::arg::Dict<&str, dbus::arg::Dict<&str, dbus::arg::Variant<()>, _>, _> =
        response.get1().unwrap();

    println!(":?", test);

导致此错误:

error[E0277]: the trait bound `(): dbus::arg::Get<'_>` is not satisfied
  --> src/main.rs:20:18
   |
20 |         response.get1().unwrap();
   |                  ^^^^ the trait `dbus::arg::Get<'_>` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Variant<()>`
   = note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Dict<'_, &str, dbus::arg::Variant<()>, dbus::arg::Iter<'_>>`
   = note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Dict<'_, &str, dbus::arg::Dict<'_, &str, dbus::arg::Variant<()>, dbus::arg::Iter<'_>>,     dbus::arg::Iter<'_>>`

如何获取连接信息?

我认为Variant 的全部意义在于它可以保存不同类型的数据?我做错了什么?

如果我用&amp;str 替换Variant 类型(),它会打印出Dict(Iter("Unknown?!", "Unknown?!", "Unknown?!", "Unknown?!", "Unknown?!"), PhantomData)Unknown?! 的值是多少?

API for Dict 也表示

从迭代器创建一个新的Dict。追加时使用迭代器。

我应该如何/应该改用这个?我确实设法取得了一些进展,也许是天真?

我的代码现在看起来像这样:

extern crate dbus;
extern crate network_manager;

#[derive(Default, Debug)]
struct Connection 
    path: String,
    id: String,
    uuid: String,
    ssid: String,
    interface: String,
    security: String,
    psk: String, // Only used when creating a new connection


fn main() 
    let connection = Connection 
        path: "/org/freedesktop/NetworkManager/Settings/0".to_string(),
        ..Default::default()
    ;

    let message = dbus::Message::new_method_call("org.freedesktop.NetworkManager",
                                                 connection.path.clone(),
                                                 "org.freedesktop.NetworkManager.Settings.\
                                                  Connection",
                                                 "GetSettings")
        .unwrap();

    let response = dbus::Connection::get_private(dbus::BusType::System)
        .unwrap()
        .send_with_reply_and_block(message, 2000)
        .unwrap();

    let mut outer_array_iter = response.iter_init().recurse(97).unwrap();
    loop 
        let mut outer_dict_iter = outer_array_iter.recurse(101).unwrap();
        outer_dict_iter.next();

        let mut inner_array_iter = outer_dict_iter.recurse(97).unwrap();
        loop 
            let mut inner_dict_iter = inner_array_iter.recurse(101).unwrap();

            let key = inner_dict_iter.read::<&str>().unwrap();
            match key 
                "id" => 
                    let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
                    println!("id :?", val);
                
                "uuid" => 
                    let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
                    println!("uuid :?", val);
                
                "ssid" => 
                    let val: dbus::arg::Variant<dbus::arg::Array<i32, _>> = inner_dict_iter.read()
                        .unwrap();
                    println!("ssid :?", val);
                
                "type" => 
                    let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
                    println!("interface :?", val);
                
                "security" => 
                    let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
                    println!("security :?", val);
                
                _ => (),
            

            if !(inner_array_iter.next()) 
                break;
            
        

        if !(outer_array_iter.next()) 
            break;
        
    

    println!(":?", connection);

打印出来:

id Variant("Plough Way Cafe")
uuid Variant("e078808e-626f-4be9-bbb4-5e48b1d626de")
interface Variant("802-11-wireless")
ssid Variant(Array(Iter("u8", "u8", "u8", "u8", "u8", "u8", "u8", "u8"), PhantomData))
security Variant("802-11-wireless-security")
Connection  path: "/org/freedesktop/NetworkManager/Settings/0", id: "", uuid: "", ssid: "", interface: "", security: "", psk: "" 

如何将数据从Variant 中取出并放入我的connection 结构中?有没有更好的方法来使用迭代器,因为这感觉很脆弱?

【问题讨论】:

你上面的函数中response的类型是什么?因为编译器似乎暗示它是() @MatthieuM。我添加了这一行let x: () = response;,错误为expected (), found struct `dbus::Message`responsedbus::Message 啊,我的错误,进一步挖掘,似乎Get 被递归应用,直到它到达Variant&lt;()&gt;,这就是() 的来源。 我在用这行替换test 的赋值时编译它:let test: Array&lt;&amp;str, _&gt; = response.get1().unwrap();(从this code example 得到)。这有帮助吗? 啊,显然这会导致相同的打印输出:Array(Iter("Unknown?!", "Unknown?!", "Unknown?!", "Unknown?!"), PhantomData).. 【参考方案1】:

这里是如何通过修改第一个示例来修复它:

let test: dbus::arg::Dict<&str, dbus::arg::Dict<&str, dbus::arg::Variant<dbus::arg::Iter>, _>, _> =
response.get1().unwrap();

for (k1, v1) in test 
    println!("outer key = :?", k1);
    for (k2, v2) in v1 
        println!("    inner key = :?, inner type = :?, string value = :?", k2, v2, v2.0.clone().get::<&str>());
    

如果您在获取变体时不知道变体中的内容,则需要使用Variant&lt;Iter&gt;。然后,您必须使用 get::&lt;&amp;str&gt;(), get::&lt;u32&gt;() 等来检索变体中的实际值。

【讨论】:

以上是关于使用 Rust DBUS 库时,不满足 trait bound `dbus::arg::Get`的主要内容,如果未能解决你的问题,请参考以下文章

Rust impl trait

Rust 中 trait 的冲突实现

Rust-线程:使用Sync和Send trait的可扩展并发

Rust-线程:使用Sync和Send trait的可扩展并发

Rust-线程:使用Sync和Send trait的可扩展并发

rust trait 熟识系列:一日一trait之Seek trait