Skip to content

Commit 635d5cd

Browse files
authored
Merge pull request #1761 from carlosmn/cmn/properties-default
Allow specifying a default via `Default` in a field within `Properties`
2 parents 7507de5 + f5003d8 commit 635d5cd

File tree

4 files changed

+95
-8
lines changed

4 files changed

+95
-8
lines changed

glib-macros/src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,9 +525,12 @@ pub fn closure_local(item: TokenStream) -> TokenStream {
525525
/// }
526526
/// ```
527527
///
528-
/// When using the [`Properties`] macro with enums that derive [`Enum`], the default value must be
529-
/// explicitly set via the `builder` parameter of the `#[property]` attribute. See
530-
/// [here](Properties#supported-types) for details.
528+
/// When using the [`Properties`] macro with enums that derive [`Enum`], the
529+
/// default value can be explicitly set via the `builder` parameter of the
530+
/// `#[property]` attribute. If the enum implements or derives
531+
/// `Default`, you can specify that should be the default value
532+
/// via the `default` parameter. See [here](Properties#supported-types) for
533+
/// details.
531534
///
532535
/// An enum can be registered as a dynamic type by setting the derive macro
533536
/// helper attribute `enum_dynamic`:
@@ -1333,7 +1336,8 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
13331336
/// | `construct` | Specify that the property is construct property. Ensures that the property is always set during construction (if not explicitly then the default value is used). The use of a custom internal setter is supported. | | `#[property(get, construct)]` or `#[property(get, set = set_prop, construct)]` |
13341337
/// | `construct_only` | Specify that the property is construct only. This will not generate a public setter and only allow the property to be set during object construction. The use of a custom internal setter is supported. | | `#[property(get, construct_only)]` or `#[property(get, set = set_prop, construct_only)]` |
13351338
/// | `builder(<required-params>)[.ident]*` | Used to input required params or add optional Param Spec builder fields | | `#[property(builder(SomeEnum::default()))]`, `#[builder().default_value(1).minimum(0).maximum(5)]`, etc. |
1336-
/// | `default` | Sets the `default_value` field of the Param Spec builder | | `#[property(default = 1)]` |
1339+
/// | `default` | Sets the param spec builder field to the default value | | `#[property(default)]` |
1340+
/// | `default = expr` | Sets the `default_value` field of the Param Spec builder | | `#[property(default = 1)]` |
13371341
/// | `<optional-pspec-builder-fields> = expr` | Used to add optional Param Spec builder fields | | `#[property(minimum = 0)` , `#[property(minimum = 0, maximum = 1)]`, etc. |
13381342
/// | `<optional-pspec-builder-fields>` | Used to add optional Param Spec builder fields | | `#[property(explicit_notify)]` , `#[property(construct_only)]`, etc. |
13391343
///
@@ -1443,6 +1447,8 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
14431447
/// smart_pointer: Rc<RefCell<String>>,
14441448
/// #[property(get, set, builder(MyEnum::Val))]
14451449
/// my_enum: Cell<MyEnum>,
1450+
/// #[property(get, set, default)]
1451+
/// my_enum_with_default: Cell<MyEnum>,
14461452
/// /// # Getter
14471453
/// ///
14481454
/// /// Get the value of the property `extra_comments`

glib-macros/src/properties.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ enum PropAttr {
138138

139139
// ident = "literal"
140140
Name(syn::LitStr),
141+
142+
// ident
143+
Default,
141144
}
142145

143146
impl Parse for PropAttr {
@@ -194,6 +197,7 @@ impl Parse for PropAttr {
194197
),
195198
))
196199
}
200+
"default" => PropAttr::Default,
197201
_ => PropAttr::BuilderField((name, None)),
198202
}
199203
};
@@ -213,6 +217,7 @@ struct ReceivedAttrs {
213217
name: Option<syn::LitStr>,
214218
builder: Option<(Punctuated<syn::Expr, Token![,]>, TokenStream2)>,
215219
builder_fields: HashMap<syn::Ident, Option<syn::Expr>>,
220+
use_default: bool,
216221
}
217222

218223
impl Parse for ReceivedAttrs {
@@ -244,6 +249,9 @@ impl ReceivedAttrs {
244249
PropAttr::BuilderField((ident, expr)) => {
245250
self.builder_fields.insert(ident, expr);
246251
}
252+
PropAttr::Default => {
253+
self.use_default = true;
254+
}
247255
}
248256
}
249257
}
@@ -265,6 +273,7 @@ struct PropDesc {
265273
builder: Option<(Punctuated<syn::Expr, Token![,]>, TokenStream2)>,
266274
builder_fields: HashMap<syn::Ident, Option<syn::Expr>>,
267275
is_construct_only: bool,
276+
use_default: bool,
268277
}
269278

270279
impl PropDesc {
@@ -286,6 +295,7 @@ impl PropDesc {
286295
name,
287296
builder,
288297
builder_fields,
298+
use_default,
289299
} = attrs;
290300

291301
let is_construct_only = builder_fields.iter().any(|(k, _)| *k == "construct_only");
@@ -333,6 +343,7 @@ impl PropDesc {
333343
builder,
334344
builder_fields,
335345
is_construct_only,
346+
use_default,
336347
})
337348
}
338349
fn is_overriding(&self) -> bool {
@@ -343,7 +354,11 @@ impl PropDesc {
343354
fn expand_param_spec(prop: &PropDesc) -> TokenStream2 {
344355
let crate_ident = crate_ident_new();
345356
let PropDesc {
346-
ty, name, builder, ..
357+
ty,
358+
name,
359+
builder,
360+
use_default,
361+
..
347362
} = prop;
348363
let stripped_name = strip_raw_prefix_from_name(name);
349364

@@ -385,9 +400,20 @@ fn expand_param_spec(prop: &PropDesc) -> TokenStream2 {
385400
let builder_fields = prop.builder_fields.iter().map(|(k, v)| quote!(.#k(#v)));
386401

387402
let span = prop.attrs_span;
403+
404+
// Figure out if we should use the default version or the one that explicitly sets the `Default` value.
405+
let (trait_name, fn_name) = if *use_default {
406+
(
407+
quote!(HasParamSpecDefaulted),
408+
quote!(param_spec_builder_defaulted),
409+
)
410+
} else {
411+
(quote!(HasParamSpec), quote!(param_spec_builder))
412+
};
413+
388414
quote_spanned! {span=>
389-
<<#ty as #crate_ident::property::Property>::Value as #crate_ident::prelude::HasParamSpec>
390-
::param_spec_builder() #builder_call
415+
<<#ty as #crate_ident::property::Property>::Value as #crate_ident::#trait_name>
416+
::#fn_name() #builder_call
391417
#rw_flags
392418
#(#builder_fields)*
393419
.build()

glib-macros/tests/properties.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ mod foo {
6969
pub enum SimpleEnum {
7070
#[default]
7171
One,
72+
Two,
7273
}
7374

7475
#[derive(Default, Clone)]
@@ -129,10 +130,14 @@ mod foo {
129130
builder_fields_without_builder: RefCell<u32>,
130131
#[property(get, set, builder('c'))]
131132
builder_with_required_param: RefCell<char>,
133+
#[property(get, set, default)]
134+
char_default: RefCell<char>,
132135
#[property(get, set)]
133136
boxed: RefCell<SimpleBoxedString>,
134-
#[property(get, set, builder(SimpleEnum::One))]
137+
#[property(get, set, builder(SimpleEnum::Two))]
135138
fenum: RefCell<SimpleEnum>,
139+
#[property(get, set, default)]
140+
fenum_default: RefCell<SimpleEnum>,
136141
#[property(get, set, nullable)]
137142
object: RefCell<Option<glib::Object>>,
138143
#[property(get, set, nullable)]
@@ -206,6 +211,8 @@ mod foo {
206211

207212
#[test]
208213
fn props() {
214+
use crate::foo::SimpleEnum;
215+
209216
let myfoo: foo::Foo = glib::object::Object::new();
210217

211218
// Read values
@@ -274,6 +281,25 @@ fn props() {
274281
"hello".to_string()
275282
);
276283

284+
assert_eq!(
285+
myfoo
286+
.find_property("fenum")
287+
.unwrap()
288+
.default_value()
289+
.get::<SimpleEnum>()
290+
.unwrap(),
291+
SimpleEnum::Two
292+
);
293+
assert_eq!(
294+
myfoo
295+
.find_property("fenum_default")
296+
.unwrap()
297+
.default_value()
298+
.get::<SimpleEnum>()
299+
.unwrap(),
300+
SimpleEnum::One
301+
);
302+
277303
// numeric builder
278304
assert_eq!(
279305
myfoo

glib/src/param_spec.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,35 @@ pub trait HasParamSpec {
21742174
fn param_spec_builder() -> Self::BuilderFn;
21752175
}
21762176

2177+
// unless a custom `default` attribute is specified, the macro will use this trait.
2178+
pub trait HasParamSpecDefaulted: HasParamSpec + Default {
2179+
type BuilderFnDefaulted;
2180+
fn param_spec_builder_defaulted() -> Self::BuilderFnDefaulted;
2181+
}
2182+
2183+
// Manually implement the trait for every Enum
2184+
impl<
2185+
T: HasParamSpec<ParamSpec = ParamSpecEnum>
2186+
+ StaticType
2187+
+ FromGlib<i32>
2188+
+ IntoGlib<GlibType = i32>
2189+
+ Default,
2190+
> HasParamSpecDefaulted for T
2191+
{
2192+
type BuilderFnDefaulted = fn(name: &str) -> ParamSpecEnumBuilder<T>;
2193+
fn param_spec_builder_defaulted() -> Self::BuilderFnDefaulted {
2194+
|name| Self::ParamSpec::builder(name)
2195+
}
2196+
}
2197+
2198+
// Manually implement the trait for chars
2199+
impl HasParamSpecDefaulted for char {
2200+
type BuilderFnDefaulted = fn(name: &str) -> ParamSpecUnicharBuilder;
2201+
fn param_spec_builder_defaulted() -> Self::BuilderFnDefaulted {
2202+
|name| Self::ParamSpec::builder(name, Default::default())
2203+
}
2204+
}
2205+
21772206
impl<T: crate::value::ToValueOptional + HasParamSpec> HasParamSpec for Option<T> {
21782207
type ParamSpec = T::ParamSpec;
21792208
type SetValue = T::SetValue;

0 commit comments

Comments
 (0)