Skip to content

Commit 5dc6382

Browse files
committed
feat(property): add get, get_ref and set attributes
these attributes are used to set custom getter and setter.
1 parent 1f3b19d commit 5dc6382

File tree

2 files changed

+234
-35
lines changed

2 files changed

+234
-35
lines changed

gdnative-derive/src/native_script.rs

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use proc_macro::TokenStream;
22
use proc_macro2::TokenStream as TokenStream2;
33

44
use syn::spanned::Spanned;
5-
use syn::{Data, DeriveInput, Fields, Ident, Meta, MetaList, NestedMeta, Path, Stmt, Type};
5+
use syn::{Data, DeriveInput, Expr, Fields, Ident, Meta, MetaList, NestedMeta, Path, Stmt, Type};
66

77
mod property_args;
8-
use property_args::{PropertyAttrArgs, PropertyAttrArgsBuilder};
8+
use property_args::{PropertyAttrArgs, PropertyAttrArgsBuilder, PropertyGet, PropertySet};
99

1010
pub(crate) struct DeriveData {
1111
pub(crate) name: Ident,
@@ -66,46 +66,70 @@ pub(crate) fn derive_native_class(derive_input: &DeriveInput) -> Result<TokenStr
6666
.default
6767
.map(|default_value| quote!(.with_default(#default_value)));
6868
let with_hint = config.hint.map(|hint_fn| quote!(.with_hint(#hint_fn())));
69-
7069
let with_usage = if config.no_editor {
7170
Some(quote!(.with_usage(::gdnative::export::PropertyUsage::NOEDITOR)))
7271
} else {
7372
None
7473
};
75-
74+
// if both of them are not set, i.e. `#[property]`. implicitly use both getter/setter
75+
let (get, set) = if config.get.is_none() && config.set.is_none() {
76+
(Some(PropertyGet::Default), Some(PropertySet::Default))
77+
} else {
78+
(config.get, config.set)
79+
};
7680
let before_get: Option<Stmt> = config
7781
.before_get
7882
.map(|path_expr| parse_quote!(#path_expr(this, _owner);));
79-
8083
let after_get: Option<Stmt> = config
8184
.after_get
8285
.map(|path_expr| parse_quote!(#path_expr(this, _owner);));
83-
86+
let with_getter = get.map(|get| {
87+
let register_fn = match get {
88+
PropertyGet::Owned(_) => quote!(with_getter),
89+
_ => quote!(with_ref_getter),
90+
};
91+
let get: Expr = match get {
92+
PropertyGet::Default => parse_quote!(&this.#ident),
93+
PropertyGet::Owned(path_expr) | PropertyGet::Ref(path_expr) => {
94+
parse_quote!(#path_expr(this, _owner))
95+
}
96+
};
97+
quote!(
98+
.#register_fn(|this: &#name, _owner: ::gdnative::object::TRef<Self::Base>| {
99+
#before_get
100+
let res = #get;
101+
#after_get
102+
res
103+
})
104+
)
105+
});
84106
let before_set: Option<Stmt> = config
85107
.before_set
86108
.map(|path_expr| parse_quote!(#path_expr(this, _owner);));
87-
88109
let after_set: Option<Stmt> = config
89110
.after_set
90111
.map(|path_expr| parse_quote!(#path_expr(this, _owner);));
112+
let with_setter = set.map(|set| {
113+
let set: Stmt = match set {
114+
PropertySet::Default => parse_quote!(this.#ident = v;),
115+
PropertySet::WithPath(path_expr) => parse_quote!(#path_expr(this, _owner, v);),
116+
};
117+
quote!(
118+
.with_setter(|this: &mut #name, _owner: ::gdnative::object::TRef<Self::Base>, v| {
119+
#before_set
120+
#set
121+
#after_set
122+
}))
123+
});
91124

92125
let label = config.path.unwrap_or_else(|| format!("{}", ident));
93126
quote!({
94127
builder.property(#label)
95128
#with_default
96129
#with_hint
97130
#with_usage
98-
.with_ref_getter(|this: &#name, _owner: ::gdnative::object::TRef<Self::Base>| {
99-
#before_get
100-
let res = &this.#ident;
101-
#after_get
102-
res
103-
})
104-
.with_setter(|this: &mut #name, _owner: ::gdnative::object::TRef<Self::Base>, v| {
105-
#before_set
106-
this.#ident = v;
107-
#after_set
108-
})
131+
#with_getter
132+
#with_setter
109133
.done();
110134
})
111135
});
@@ -221,8 +245,8 @@ fn parse_derive_input(input: &DeriveInput) -> Result<DeriveData, syn::Error> {
221245

222246
match meta {
223247
Meta::List(MetaList { nested, .. }) => {
224-
let attr_args_builder =
225-
property_args.get_or_insert_with(PropertyAttrArgsBuilder::default);
248+
let attr_args_builder = property_args
249+
.get_or_insert_with(|| PropertyAttrArgsBuilder::new(&field.ty));
226250

227251
for arg in &nested {
228252
if let NestedMeta::Meta(Meta::NameValue(ref pair)) = arg {
@@ -236,7 +260,8 @@ fn parse_derive_input(input: &DeriveInput) -> Result<DeriveData, syn::Error> {
236260
}
237261
}
238262
Meta::Path(_) => {
239-
property_args.get_or_insert_with(PropertyAttrArgsBuilder::default);
263+
property_args
264+
.get_or_insert_with(|| PropertyAttrArgsBuilder::new(&field.ty));
240265
}
241266
m => {
242267
let msg = format!("Unexpected meta variant: {:?}", m);
@@ -337,4 +362,49 @@ mod tests {
337362

338363
parse_derive_input(&input).unwrap();
339364
}
365+
366+
#[test]
367+
fn derive_property_get_set() {
368+
let input: TokenStream2 = syn::parse_str(
369+
r#"
370+
#[inherit(Node)]
371+
struct Foo {
372+
#[property(get = "get_bar", set = "set_bar")]
373+
bar: i64,
374+
}"#,
375+
)
376+
.unwrap();
377+
let input: DeriveInput = syn::parse2(input).unwrap();
378+
parse_derive_input(&input).unwrap();
379+
}
380+
381+
#[test]
382+
fn derive_property_default_get_set() {
383+
let input: TokenStream2 = syn::parse_str(
384+
r#"
385+
#[inherit(Node)]
386+
struct Foo {
387+
#[property(get, set)]
388+
bar: i64,
389+
}"#,
390+
)
391+
.unwrap();
392+
let input: DeriveInput = syn::parse2(input).unwrap();
393+
parse_derive_input(&input).unwrap();
394+
}
395+
396+
#[test]
397+
fn derive_property_default_get_ref() {
398+
let input: TokenStream2 = syn::parse_str(
399+
r#"
400+
#[inherit(Node)]
401+
struct Foo {
402+
#[property(get_ref = "Self::get_bar")]
403+
bar: i64,
404+
}"#,
405+
)
406+
.unwrap();
407+
let input: DeriveInput = syn::parse2(input).unwrap();
408+
parse_derive_input(&input).unwrap();
409+
}
340410
}

0 commit comments

Comments
 (0)