DBUS ObjectPath - "ambiguous associated type" error


#1

Hey,

I am trying to make use of this DBUS lib to interact with SystemD and grab the Object Path of the NetworkManager.service.

This is my code so far:

let c = Connection::get_private(BusType::System).unwrap();
let mut m = Message::new_method_call("org.freedesktop.systemd1",
                                     "/org/freedesktop/systemd1",
                                     "org.freedesktop.systemd1.Manager",
                                     "GetUnit")
    .unwrap();
m.append_items(&["NetworkManager.service".into()]);

let r = c.send_with_reply_and_block(m, 2000).unwrap().get_items();

println!("{:?}", r);

which prints:
[ObjectPath(Path("/org/freedesktop/systemd1/unit/NetworkManager_2eservice"))]

I need the "/org/freedesktop/systemd1/unit/NetworkManager_2eservice" part and as its an ObjectPath I thought this would work:

let c = Connection::get_private(BusType::System).unwrap();
let mut m = Message::new_method_call("org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
                                 "GetUnit")
    .unwrap();
m.append_items(&["NetworkManager.service".into()]);

let r = c.send_with_reply_and_block(m, 2000).unwrap();

let p: ObjectPath<MethodType::Method, DataType::ObjectPath>  = r.get1().unwrap();

println!("{:?}", p);

but it throws an error during compile:

error[E0223]: ambiguous associated type
  --> src/service/mod.rs:65:23
   |
65 |     let p: ObjectPath<MethodType::Method, DataType::ObjectPath>  = r.get1().unwrap();
   |                       ^^^^^^^^^^^^^^^^^^ ambiguous associated type
   |
   = note: specify the type using the syntax `<Type as service::dbus::tree::MethodType>::Method`

error[E0223]: ambiguous associated type
  --> src/service/mod.rs:65:43
   |
65 |     let p: ObjectPath<MethodType::Method, DataType::ObjectPath>  = r.get1().unwrap();
   |                                           ^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
   |
   = note: specify the type using the syntax `<Type as service::dbus::tree::DataType>::ObjectPath`

error: aborting due to 2 previous errors

error: Could not compile `network_manager`.

I’m totally confused as to the correct way to get the object path out of the response, help!!!

Thanks in advance :smile:


#2

First of all, I want to say, please don’t spell systemd as “SystemD”. Here’s what the official documentation says:

Yes, it is written systemd, not system D or System D, or even SystemD. And it isn’t system d either. Why? Because it’s a system daemon, and under Unix/Linux those are in lower case, and get suffixed with a lower case d. And since systemd manages the system, it’s called systemd. It’s that simple. But then again, if all that appears too simple to you, call it (but never spell it!) System Five Hundred since D is the roman numeral for 500 (this also clarifies the relation to System V, right?). The only situation where we find it OK to use an uppercase letter in the name (but don’t like it either) is if you start a sentence with systemd. On high holidays you may also spell it sÿstëmd. But then again, Système D is not an acceptable spelling and something completely different (though kinda fitting).

Now on to the question. In your first example, r is of type Vec<MessageItem>, and its first (and only) element is MessageItem::ObjectPath(p). That is the ObjectPath variant of the MessageItem enum, not the dbus::tree::ObjectPath struct that is intended for server-side usage (the naming here is confusing, I must admit).

Thus, a code like this would work for your need:

let r = c.send_with_reply_and_block(m, 2000).unwrap();
let p: Path = r.get1().unwrap();
println!("{:?}", p);

This prints: Path("/org/freedesktop/systemd1/unit/NetworkManager_2eservice") - exactly what you’d expect.


#3

Perfect, thank you very much. I am still getting my head around writing code using the API documentation style :stuck_out_tongue: