Skip to content
This repository was archived by the owner on Mar 4, 2024. It is now read-only.

Commit a0d0926

Browse files
authored
gio: Use builder pattern for Settings::bind() (#210)
This now wraps `g_settings_bind_with_mapping`, so mapping can optionally be specified.
1 parent 3d8b887 commit a0d0926

File tree

3 files changed

+132
-36
lines changed

3 files changed

+132
-36
lines changed

gio/Gir.toml

+6
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,12 @@ status = "generate"
870870
name = "get_value"
871871
[object.function.return]
872872
nullable = false
873+
[[object.function]]
874+
name = "bind"
875+
manual = true
876+
[[object.function]]
877+
name = "bind_with_mapping"
878+
manual = true
873879

874880
[[object]]
875881
name = "Gio.SettingsSchemaKey"

gio/src/auto/settings.rs

-35
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use crate::Action;
66
use crate::SettingsBackend;
7-
use crate::SettingsBindFlags;
87
use crate::SettingsSchema;
98
use glib::object::Cast;
109
use glib::object::IsA;
@@ -101,18 +100,6 @@ pub trait SettingsExt: 'static {
101100
#[doc(alias = "g_settings_apply")]
102101
fn apply(&self);
103102

104-
#[doc(alias = "g_settings_bind")]
105-
fn bind<P: IsA<glib::Object>>(
106-
&self,
107-
key: &str,
108-
object: &P,
109-
property: &str,
110-
flags: SettingsBindFlags,
111-
);
112-
113-
//#[doc(alias = "g_settings_bind_with_mapping")]
114-
//fn bind_with_mapping<P: IsA<glib::Object>, Q: Fn(&glib::Value, &glib::Variant) -> bool + 'static, R: Fn(&glib::Value, &glib::VariantType) -> glib::Variant + 'static>(&self, key: &str, object: &P, property: &str, flags: SettingsBindFlags, get_mapping: Q, set_mapping: R);
115-
116103
#[doc(alias = "g_settings_bind_writable")]
117104
fn bind_writable<P: IsA<glib::Object>>(
118105
&self,
@@ -275,28 +262,6 @@ impl<O: IsA<Settings>> SettingsExt for O {
275262
}
276263
}
277264

278-
fn bind<P: IsA<glib::Object>>(
279-
&self,
280-
key: &str,
281-
object: &P,
282-
property: &str,
283-
flags: SettingsBindFlags,
284-
) {
285-
unsafe {
286-
ffi::g_settings_bind(
287-
self.as_ref().to_glib_none().0,
288-
key.to_glib_none().0,
289-
object.as_ref().to_glib_none().0,
290-
property.to_glib_none().0,
291-
flags.to_glib(),
292-
);
293-
}
294-
}
295-
296-
//fn bind_with_mapping<P: IsA<glib::Object>, Q: Fn(&glib::Value, &glib::Variant) -> bool + 'static, R: Fn(&glib::Value, &glib::VariantType) -> glib::Variant + 'static>(&self, key: &str, object: &P, property: &str, flags: SettingsBindFlags, get_mapping: Q, set_mapping: R) {
297-
// unsafe { TODO: call ffi:g_settings_bind_with_mapping() }
298-
//}
299-
300265
fn bind_writable<P: IsA<glib::Object>>(
301266
&self,
302267
key: &str,

gio/src/settings.rs

+126-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,119 @@
1-
use crate::{Settings, SettingsExt};
1+
use crate::{Settings, SettingsBindFlags, SettingsExt};
2+
use glib::prelude::*;
3+
use glib::translate::{from_glib_borrow, from_glib_none, ToGlib, ToGlibPtr};
24
use glib::variant::FromVariant;
35
use glib::{BoolError, IsA, ToVariant};
46

7+
pub struct BindingBuilder<'a> {
8+
settings: &'a Settings,
9+
key: &'a str,
10+
object: &'a glib::Object,
11+
property: &'a str,
12+
flags: SettingsBindFlags,
13+
get_mapping: Option<Box<dyn Fn(&glib::Variant, glib::Type) -> Option<glib::Value>>>,
14+
set_mapping: Option<Box<dyn Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant>>>,
15+
}
16+
17+
impl<'a> BindingBuilder<'a> {
18+
pub fn flags(mut self, flags: SettingsBindFlags) -> Self {
19+
self.flags = flags;
20+
self
21+
}
22+
23+
pub fn get_mapping<F: Fn(&glib::Variant, glib::Type) -> Option<glib::Value> + 'static>(
24+
mut self,
25+
f: F,
26+
) -> Self {
27+
self.get_mapping = Some(Box::new(f));
28+
self
29+
}
30+
31+
pub fn set_mapping<
32+
F: Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant> + 'static,
33+
>(
34+
mut self,
35+
f: F,
36+
) -> Self {
37+
self.set_mapping = Some(Box::new(f));
38+
self
39+
}
40+
41+
pub fn build(self) {
42+
type Mappings = (
43+
Option<Box<dyn Fn(&glib::Variant, glib::Type) -> Option<glib::Value>>>,
44+
Option<Box<dyn Fn(&glib::Value, glib::VariantType) -> Option<glib::Variant>>>,
45+
);
46+
unsafe extern "C" fn bind_with_mapping_get_trampoline(
47+
value: *mut glib::gobject_ffi::GValue,
48+
variant: *mut glib::ffi::GVariant,
49+
user_data: glib::ffi::gpointer,
50+
) -> glib::ffi::gboolean {
51+
let user_data = &*(user_data as *const Mappings);
52+
let f = user_data.0.as_ref().unwrap();
53+
let value = &mut *(value as *mut glib::Value);
54+
if let Some(v) = f(&*from_glib_borrow(variant), value.type_()) {
55+
*value = v;
56+
true
57+
} else {
58+
false
59+
}
60+
.to_glib()
61+
}
62+
unsafe extern "C" fn bind_with_mapping_set_trampoline(
63+
value: *const glib::gobject_ffi::GValue,
64+
variant_type: *const glib::ffi::GVariantType,
65+
user_data: glib::ffi::gpointer,
66+
) -> *mut glib::ffi::GVariant {
67+
let user_data = &*(user_data as *const Mappings);
68+
let f = user_data.1.as_ref().unwrap();
69+
let value = &*(value as *const glib::Value);
70+
f(value, from_glib_none(variant_type)).to_glib_full()
71+
}
72+
unsafe extern "C" fn destroy_closure(ptr: *mut libc::c_void) {
73+
Box::<Mappings>::from_raw(ptr as *mut _);
74+
}
75+
let get_trampoline: Option<unsafe extern "C" fn(_, _, _) -> _> =
76+
if self.get_mapping.is_none() {
77+
None
78+
} else {
79+
Some(bind_with_mapping_get_trampoline)
80+
};
81+
let set_trampoline: Option<unsafe extern "C" fn(_, _, _) -> _> =
82+
if self.set_mapping.is_none() {
83+
None
84+
} else {
85+
Some(bind_with_mapping_set_trampoline)
86+
};
87+
let mappings: Mappings = (self.get_mapping, self.set_mapping);
88+
unsafe {
89+
ffi::g_settings_bind_with_mapping(
90+
self.settings.to_glib_none().0,
91+
self.key.to_glib_none().0,
92+
self.object.to_glib_none().0,
93+
self.property.to_glib_none().0,
94+
self.flags.to_glib(),
95+
get_trampoline,
96+
set_trampoline,
97+
Box::into_raw(Box::new(mappings)) as *mut libc::c_void,
98+
Some(destroy_closure),
99+
)
100+
}
101+
}
102+
}
103+
5104
pub trait SettingsExtManual {
6105
fn get<U: FromVariant>(&self, key: &str) -> U;
7106

8107
fn set<U: ToVariant>(&self, key: &str, value: &U) -> Result<(), BoolError>;
108+
109+
#[doc(alias = "g_settings_bind")]
110+
#[doc(alias = "g_settings_bind_with_mapping")]
111+
fn bind<'a, P: IsA<glib::Object>>(
112+
&'a self,
113+
key: &'a str,
114+
object: &'a P,
115+
property: &'a str,
116+
) -> BindingBuilder<'a>;
9117
}
10118

11119
impl<O: IsA<Settings>> SettingsExtManual for O {
@@ -23,6 +131,23 @@ impl<O: IsA<Settings>> SettingsExtManual for O {
23131
fn set<U: ToVariant>(&self, key: &str, value: &U) -> Result<(), BoolError> {
24132
self.set_value(key, &value.to_variant())
25133
}
134+
135+
fn bind<'a, P: IsA<glib::Object>>(
136+
&'a self,
137+
key: &'a str,
138+
object: &'a P,
139+
property: &'a str,
140+
) -> BindingBuilder<'a> {
141+
BindingBuilder {
142+
settings: self.upcast_ref(),
143+
key,
144+
object: object.upcast_ref(),
145+
property,
146+
flags: SettingsBindFlags::DEFAULT,
147+
get_mapping: None,
148+
set_mapping: None,
149+
}
150+
}
26151
}
27152

28153
#[cfg(test)]

0 commit comments

Comments
 (0)