gtk-rs-core
gtk-rs-core copied to clipboard
Generate bind_property helper
I think it would be useful to generate the following function with the Properties macro
fn bind_$name(&self, target: impl IsA<Object>, target_property: &str) -> BindingBuilder {
self.bind_property($name, target, target_property)
}
To avoid people mistyping the property name or forgetting to update it somewhere and be surprised by a crash at runtime
cc @ranfdev
The user could still mistype the target property string though. So this doesn't fully solve the underlying problem.
Yeah it would probably make sense to think about this a bit more so we don't add half a solution everywhere. My idea for this problem was to autogenerate some kind of enum for this, but not sure how exactly this is supposed to work with inheritance and interfaces. Needs some experimentation.
We could introduce a
struct PropertyProxy<'a, O: IsA<glib::Object>, T> {
obj: &'a O,
name: &'static str,
ty: PhantomData<T>,
}
impl<'a, O, T> PropertyProxy<'a, O, T> {
// The following will ensure the the target proxy has the same type T!
fn bind<'b, B, T>(this: Self, target: PropertyProxy<'b, B, T>) {...}
fn connect_notify(this: Self) {...}
fn param_spec() {...}
}
impl Deref for PropertyProxy {...}
impl DerefMut for PropertyProxy {...}
Then, when accessing a property from an object, instead of returning the value, we return a proxy:
let btn = gtk::Button::new();
// before
// let label: String = btn.label();
// after
let label: PropertyProxy<gtk::Button, String> = btn.label();
// we can still read the content of the property with a deref:
let label_text = *label;
Now immagine we want to bind a text input to the button's label:
let entry = gtk::Entry::new();
PropertyProxy::bind(entry.text(), btn.label());
Benefits
Everything becomes safe: the PropertyProxy can only be returned by a generated method on Button, so the property is surely valid. The bind method can ensure the two properties have the same type.
Instead of having three methods for each property:
btn.label()btn.set_label()btn.connect_label_notify()we can now just use:*btn.label()btn.label() *= String::new()PropertyProxy::connect_notify(btn.label())Note: code generation is therefore reduce by a factor of 3 or more, because gir only needs to generatebtn.label()and return a proxy.