Skip to content

Commit b848e97

Browse files
committed
extremely basic builder support
1 parent 060345a commit b848e97

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

glib-macros/src/props.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use quote::ToTokens;
88
use std::str::FromStr;
99
use syn::ext::IdentExt;
1010
use syn::parse::Parse;
11+
use syn::punctuated::Punctuated;
1112
use syn::spanned::Spanned;
1213
use syn::Token;
1314

@@ -52,6 +53,11 @@ impl std::convert::From<Option<syn::Expr>> for MaybeCustomFn {
5253
enum PropAttr {
5354
Flag(&'static str),
5455

56+
// builder(required_params).parameter(value)
57+
// becomes
58+
// Builder(Punctuated(required_params), Optionals(TokenStream))
59+
Builder(Punctuated<syn::Expr, Token![,]>, TokenStream2),
60+
5561
// ident [= expr]
5662
Get(Option<syn::Expr>),
5763
Set(Option<syn::Expr>),
@@ -121,9 +127,9 @@ impl Parse for PropAttr {
121127
} else if input.peek(syn::token::Paren) {
122128
match &*name_str {
123129
"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)
127133
}
128134
_ => panic!("Unsupported attribute list {}(...)", name_str),
129135
}
@@ -157,6 +163,7 @@ struct ReceivedAttrs {
157163
nick: Option<syn::LitStr>,
158164
blurb: Option<syn::LitStr>,
159165
default: Option<syn::Expr>,
166+
builder: Option<(Punctuated<syn::Expr, Token![,]>, TokenStream2)>,
160167
}
161168
impl ReceivedAttrs {
162169
fn new(attrs: impl IntoIterator<Item = PropAttr>) -> Self {
@@ -176,6 +183,9 @@ impl ReceivedAttrs {
176183
PropAttr::Type(ty) => self.ty = Some(ty),
177184
PropAttr::Member(member) => self.member = Some(member),
178185
PropAttr::Flag(flag) => self.flags.push(flag),
186+
PropAttr::Builder(required_params, optionals) => {
187+
self.builder = Some((required_params, optionals))
188+
}
179189
}
180190
}
181191
}
@@ -190,6 +200,7 @@ struct PropDesc {
190200
member: Option<syn::Ident>,
191201
flags: Vec<&'static str>,
192202
default: Option<syn::Expr>,
203+
builder: Option<(Punctuated<syn::Expr, Token![,]>, TokenStream2)>,
193204
}
194205
impl PropDesc {
195206
fn new(field_ident: syn::Ident, field_ty: syn::Type, attrs: ReceivedAttrs) -> Self {
@@ -203,6 +214,7 @@ impl PropDesc {
203214
nick,
204215
blurb,
205216
default,
217+
builder,
206218
} = attrs;
207219

208220
// Fill needed, but missing, attributes with calculated default values
@@ -228,6 +240,7 @@ impl PropDesc {
228240
nick,
229241
blurb,
230242
default,
243+
builder,
231244
}
232245
}
233246
}
@@ -236,24 +249,46 @@ fn expand_properties_fn(props: &[PropDesc]) -> TokenStream2 {
236249
let n_props = props.len();
237250
let properties_build_phase = props.iter().map(|prop| {
238251
let PropDesc {
239-
ty, name, nick, blurb, default, ..
252+
ty,
253+
name,
254+
nick,
255+
blurb,
256+
default,
257+
builder,
258+
..
240259
} = 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)));
244261

245262
let flags = {
246263
let write = prop.set.as_ref().map(|_| quote!(WRITABLE));
247264
let read = prop.get.as_ref().map(|_| quote!(READABLE));
248265

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+
);
253271
quote!(glib::ParamFlags::empty() #(| glib::ParamFlags::#flags_iter)*)
254272
};
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)));
255288
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()
257292
}
258293
});
259294
quote!(

0 commit comments

Comments
 (0)