@@ -8,6 +8,7 @@ use quote::ToTokens;
8
8
use std:: str:: FromStr ;
9
9
use syn:: ext:: IdentExt ;
10
10
use syn:: parse:: Parse ;
11
+ use syn:: punctuated:: Punctuated ;
11
12
use syn:: spanned:: Spanned ;
12
13
use syn:: Token ;
13
14
@@ -52,6 +53,11 @@ impl std::convert::From<Option<syn::Expr>> for MaybeCustomFn {
52
53
enum PropAttr {
53
54
Flag ( & ' static str ) ,
54
55
56
+ // builder(required_params).parameter(value)
57
+ // becomes
58
+ // Builder(Punctuated(required_params), Optionals(TokenStream))
59
+ Builder ( Punctuated < syn:: Expr , Token ! [ , ] > , TokenStream2 ) ,
60
+
55
61
// ident [= expr]
56
62
Get ( Option < syn:: Expr > ) ,
57
63
Set ( Option < syn:: Expr > ) ,
@@ -121,9 +127,9 @@ impl Parse for PropAttr {
121
127
} else if input. peek ( syn:: token:: Paren ) {
122
128
match & * name_str {
123
129
"builder" => {
124
- let content ;
125
- syn :: parenthesized! ( content in input) ;
126
- unimplemented ! ( "builder" ) ;
130
+ let required = input . parse_terminated ( syn :: Expr :: parse ) ? ;
131
+ let rest : TokenStream2 = input. parse ( ) ? ;
132
+ PropAttr :: Builder ( required , rest )
127
133
}
128
134
_ => panic ! ( "Unsupported attribute list {}(...)" , name_str) ,
129
135
}
@@ -157,6 +163,7 @@ struct ReceivedAttrs {
157
163
nick : Option < syn:: LitStr > ,
158
164
blurb : Option < syn:: LitStr > ,
159
165
default : Option < syn:: Expr > ,
166
+ builder : Option < ( Punctuated < syn:: Expr , Token ! [ , ] > , TokenStream2 ) > ,
160
167
}
161
168
impl ReceivedAttrs {
162
169
fn new ( attrs : impl IntoIterator < Item = PropAttr > ) -> Self {
@@ -176,6 +183,9 @@ impl ReceivedAttrs {
176
183
PropAttr :: Type ( ty) => self . ty = Some ( ty) ,
177
184
PropAttr :: Member ( member) => self . member = Some ( member) ,
178
185
PropAttr :: Flag ( flag) => self . flags . push ( flag) ,
186
+ PropAttr :: Builder ( required_params, optionals) => {
187
+ self . builder = Some ( ( required_params, optionals) )
188
+ }
179
189
}
180
190
}
181
191
}
@@ -190,6 +200,7 @@ struct PropDesc {
190
200
member : Option < syn:: Ident > ,
191
201
flags : Vec < & ' static str > ,
192
202
default : Option < syn:: Expr > ,
203
+ builder : Option < ( Punctuated < syn:: Expr , Token ! [ , ] > , TokenStream2 ) > ,
193
204
}
194
205
impl PropDesc {
195
206
fn new ( field_ident : syn:: Ident , field_ty : syn:: Type , attrs : ReceivedAttrs ) -> Self {
@@ -203,6 +214,7 @@ impl PropDesc {
203
214
nick,
204
215
blurb,
205
216
default,
217
+ builder,
206
218
} = attrs;
207
219
208
220
// Fill needed, but missing, attributes with calculated default values
@@ -228,6 +240,7 @@ impl PropDesc {
228
240
nick,
229
241
blurb,
230
242
default,
243
+ builder,
231
244
}
232
245
}
233
246
}
@@ -236,24 +249,46 @@ fn expand_properties_fn(props: &[PropDesc]) -> TokenStream2 {
236
249
let n_props = props. len ( ) ;
237
250
let properties_build_phase = props. iter ( ) . map ( |prop| {
238
251
let PropDesc {
239
- ty, name, nick, blurb, default, ..
252
+ ty,
253
+ name,
254
+ nick,
255
+ blurb,
256
+ default,
257
+ builder,
258
+ ..
240
259
} = prop;
241
- let default = default
242
- . as_ref ( )
243
- . map_or ( quote ! ( None ) , |x| quote ! ( Some ( #x) ) ) ;
260
+ let default = default. as_ref ( ) . map_or ( quote ! ( None ) , |x| quote ! ( Some ( #x) ) ) ;
244
261
245
262
let flags = {
246
263
let write = prop. set . as_ref ( ) . map ( |_| quote ! ( WRITABLE ) ) ;
247
264
let read = prop. get . as_ref ( ) . map ( |_| quote ! ( READABLE ) ) ;
248
265
249
- let flags_iter = [ write, read]
250
- . into_iter ( )
251
- . flatten ( )
252
- . chain ( prop. flags . iter ( ) . map ( |f| TokenStream2 :: from_str ( f) . unwrap ( ) ) ) ;
266
+ let flags_iter = [ write, read] . into_iter ( ) . flatten ( ) . chain (
267
+ prop. flags
268
+ . iter ( )
269
+ . map ( |f| TokenStream2 :: from_str ( f) . unwrap ( ) ) ,
270
+ ) ;
253
271
quote ! ( glib:: ParamFlags :: empty( ) #( | glib:: ParamFlags :: #flags_iter) * )
254
272
} ;
273
+
274
+ let builder_call = builder
275
+ . as_ref ( )
276
+ . cloned ( )
277
+ . map ( |( mut required_params, opts) | {
278
+ let name_expr = syn:: ExprLit {
279
+ attrs : vec ! [ ] ,
280
+ lit : syn:: Lit :: Str ( name. to_owned ( ) ) ,
281
+ } ;
282
+ required_params. insert ( 0 , name_expr. into ( ) ) ;
283
+ let required_params = required_params. iter ( ) ;
284
+
285
+ quote ! ( ( #( #required_params) * ) #opts)
286
+ } )
287
+ . unwrap_or ( quote ! ( ( #name) ) ) ;
255
288
quote ! {
256
- <<#ty as glib:: PropType >:: HasSpecType as glib:: HasParamSpec >:: Spec :: new( #name, #nick, #blurb, #default , #flags)
289
+ <<#ty as glib:: PropType >:: HasSpecType as glib:: HasParamSpec >:: Spec :: builder #builder_call
290
+ . flags( #flags)
291
+ . build( )
257
292
}
258
293
} ) ;
259
294
quote ! (
0 commit comments