dbus2 / zbus-old

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

Simplified properties interface for dbus_interface #212

Closed zeenix closed 1 year ago

zeenix commented 3 years ago

In GitLab by @danieldg on Sep 11, 2021, 22:18

After writing an interface, I wanted some helpers for the "usual case" of fields in the struct directly matching properties, and that turned in to this idea:

struct Foo {
   bar : i32,
   baz : HashMap<String, Vec<String>>,
   baz2 : HashMap<String, Vec<String>>,
   bell : Arc<Bell>,
   id: u64,
   hair: u64,
}
struct Bell {
   ding : Mutex<i32>,
   dong : Mutex<i32>,
}

#[dbus_interface(name = "org.example.Foo")]
impl Foo {
    fn split_hair(&mut self) {
        self.hair = self.hair * 2 - 1;
    }

    fn add_baz(&mut self, k : String, v : String, #[zbus(signal_context)] ctx) {
        self.baz.entry(k).or_default().push(v);
        Foo::emit_baz_changed(&ctx, &self.baz);
    }

    dbus_property!(bar: i32, readwrite);
    dbus_property!(baz: HashMap<String, Vec<String>>, readonly, emits_changed);
    // org.freedesktop.DBus.Property.EmitsChangedSignal for bar and baz are set to true

    fn add_baz2(&mut self, k : String, v : String, #[zbus(signal_context)] ctx) {
        self.baz2.entry(k).or_default().push(v);
        Foo::emit_baz2_changed(&ctx);
    }

    dbus_property!(baz2: HashMap<String, Vec<String>>, readonly, invalidates);
    // org.freedesktop.DBus.Property.EmitsChangedSignal for baz2 is set to invalidates

    dbus_property!(id: u64, readonly, const);
    // org.freedesktop.DBus.Property.EmitsChangedSignal for id is set to const

    dbus_property!(hair: u64, readonly, uncached);
    // org.freedesktop.DBus.Property.EmitsChangedSignal for hair is set to false

    // Long version 1, same as today
    #[dbus_interface(property)]
    fn dong(&self) -> i32 {
       *self.bell.dong.lock()
    }
    fn set_dong(&self, value: i32) {
       *self.bell.dong.lock() = value;
    }

    // Long version 2, value get
    dbus_property!(ding: i32, readwrite, access = fn(&self) {
       self.bell.ding.lock()
    });
    // "access" is expanded to a function or closure whose return type is
    // "-> impl Deref<Target=i32>" (-> &mut i32 for the simple case).
    // For readonly properties, "-> impl Deref" and "-> &T" would also be allowed;
    // the normal interface already handles "-> T"
}

The Bell struct is an example of a good way to have an interface whose data is available outside the ObjectServer. I think it would be useful to make this pattern (or one with Arc<Mutex<Bell>>) simpler to use; I'll make another issue for that to avoid tangling the conversation too much.

zeenix commented 1 year ago

I don't think this will go anywhere.