Skip to content

Commit a66a9b9

Browse files
authored
Support export storage and custom (#84)
Support for [@export_storage](https://docs.godotengine.org/en/stable/classes/class_@gdscript.html#class-gdscript-annotation-export-storage) and [@export_custom](https://docs.godotengine.org/en/stable/classes/class_@gdscript.html#class-gdscript-annotation-export-custom) in the form of `#[export(storage)]` and `#[export(custom(hint = ..., hint_string = ...))]`
1 parent 6ff655d commit a66a9b9

File tree

7 files changed

+252
-138
lines changed

7 files changed

+252
-138
lines changed

derive/src/attribute_ops.rs

Lines changed: 205 additions & 114 deletions
Large diffs are not rendered by default.

derive/src/impl_attribute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub fn godot_script_impl(
7474
name: stringify!(#arg_name),
7575
ty: #arg_type,
7676
class_name: <<#arg_rust_type as #godot_types::meta::GodotConvert>::Via as #godot_types::meta::GodotType>::class_id(),
77-
exported: false,
77+
usage: #godot_types::global::PropertyUsageFlags::NONE,
7878
hint: #property_hints::NONE,
7979
hint_string: String::new(),
8080
description: "",
@@ -135,7 +135,7 @@ pub fn godot_script_impl(
135135
name: #fn_name_str,
136136
ty: #fn_return_ty,
137137
class_name: <<#fn_return_ty_rust as #godot_types::meta::GodotConvert>::Via as #godot_types::meta::GodotType>::class_id(),
138-
exported: false,
138+
usage: #godot_types::global::PropertyUsageFlags::NONE,
139139
hint: #property_hints::NONE,
140140
hint_string: String::new(),
141141
description: "",

derive/src/lib.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ mod enums;
99
mod impl_attribute;
1010
mod type_paths;
1111

12-
use attribute_ops::{FieldOpts, GodotScriptOpts};
1312
use darling::{util::SpannedValue, FromAttributes, FromDeriveInput, FromMeta};
1413
use itertools::Itertools;
1514
use proc_macro2::TokenStream;
1615
use quote::{quote, quote_spanned, ToTokens};
1716
use syn::{parse_macro_input, spanned::Spanned, DeriveInput, Ident, Type};
18-
use type_paths::{godot_types, property_hints, string_name_ty, variant_ty};
1917

20-
use crate::attribute_ops::{FieldExportOps, FieldSignalOps, PropertyOpts};
18+
use crate::attribute_ops::{
19+
ExportMetadata, FieldExportOps, FieldOpts, FieldSignalOps, GodotScriptOpts, PropertyOpts,
20+
};
21+
use crate::type_paths::{godot_types, property_hints, property_usage, string_name_ty, variant_ty};
2122

2223
#[proc_macro_derive(GodotScript, attributes(export, script, prop, signal))]
2324
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
@@ -383,6 +384,7 @@ fn derive_field_metadata(
383384
) -> Result<TokenStream, TokenStream> {
384385
let godot_types = godot_types();
385386
let property_hint_ty = property_hints();
387+
let property_usage_ty = property_usage();
386388
let name = field
387389
.ident
388390
.as_ref()
@@ -392,19 +394,30 @@ fn derive_field_metadata(
392394
let rust_ty = &field.ty;
393395
let ty = rust_to_variant_type(&field.ty)?;
394396

395-
let (hint, hint_string) = is_exported
397+
let ExportMetadata {
398+
field: _,
399+
usage,
400+
hint,
401+
hint_string,
402+
} = is_exported
396403
.then(|| {
397404
let ops =
398405
FieldExportOps::from_attributes(&field.attrs).map_err(|err| err.write_errors())?;
406+
let span = field
407+
.attrs
408+
.iter()
409+
.find(|attr| attr.path().is_ident("export"))
410+
.expect("FieldExportOps already succeded")
411+
.span();
399412

400-
ops.hint(&field.ty)
413+
ops.to_export_meta(&field.ty, span)
401414
})
402415
.transpose()?
403-
.unwrap_or_else(|| {
404-
(
405-
quote_spanned!(field.span()=> #property_hint_ty::NONE),
406-
quote_spanned!(field.span()=> String::new()),
407-
)
416+
.unwrap_or_else(|| ExportMetadata {
417+
field: "",
418+
usage: quote_spanned!(field.span() => #property_usage_ty::SCRIPT_VARIABLE),
419+
hint: quote_spanned!(field.span()=> #property_hint_ty::NONE),
420+
hint_string: quote_spanned!(field.span()=> String::new()),
408421
});
409422

410423
let description = get_field_description(field);
@@ -413,7 +426,7 @@ fn derive_field_metadata(
413426
name: #name,
414427
ty: #ty,
415428
class_name: <<#rust_ty as #godot_types::meta::GodotConvert>::Via as #godot_types::meta::GodotType>::class_id(),
416-
exported: #is_exported,
429+
usage: #usage,
417430
hint: #hint,
418431
hint_string: #hint_string,
419432
description: concat!(#description),
@@ -530,7 +543,7 @@ fn extract_ident_from_type(impl_target: &syn::Type) -> Result<Ident, TokenStream
530543
Type::Macro(_) => Err(compile_error("Macro types are not supported!", impl_target)),
531544
Type::Never(_) => Err(compile_error("Never type is not supported!", impl_target)),
532545
Type::Paren(_) => Err(compile_error("Unsupported type!", impl_target)),
533-
Type::Path(ref path) => Ok(path.path.segments.last().unwrap().ident.clone()),
546+
Type::Path(path) => Ok(path.path.segments.last().unwrap().ident.clone()),
534547
Type::Ptr(_) => Err(compile_error(
535548
"Pointer types are not supported!",
536549
impl_target,

derive/src/type_paths.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,40 @@
77
use proc_macro2::TokenStream;
88
use quote::quote;
99

10+
#[inline]
1011
pub fn godot_types() -> TokenStream {
1112
quote!(::godot_rust_script::godot)
1213
}
1314

15+
#[inline]
1416
pub fn property_hints() -> TokenStream {
1517
let godot_types = godot_types();
1618

1719
quote!(#godot_types::global::PropertyHint)
1820
}
1921

22+
#[inline]
23+
pub fn property_usage() -> TokenStream {
24+
let godot_types = godot_types();
25+
26+
quote!(#godot_types::global::PropertyUsageFlags)
27+
}
28+
29+
#[inline]
2030
pub fn variant_ty() -> TokenStream {
2131
let godot_types = godot_types();
2232

2333
quote!(#godot_types::prelude::Variant)
2434
}
2535

36+
#[inline]
2637
pub fn string_name_ty() -> TokenStream {
2738
let godot_types = godot_types();
2839

2940
quote!(#godot_types::prelude::StringName)
3041
}
3142

43+
#[inline]
3244
pub fn convert_error_ty() -> TokenStream {
3345
let godot_types = godot_types();
3446

rust-script/src/interface/signals.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use godot::builtin::{
1010
Callable, Dictionary, GString, NodePath, StringName, Variant, Vector2, Vector3, Vector4,
1111
};
1212
use godot::classes::Object;
13-
use godot::global::{Error, PropertyHint};
13+
use godot::global::{Error, PropertyHint, PropertyUsageFlags};
1414
use godot::meta::{ByValue, GodotConvert, GodotType, ToGodot};
1515
use godot::obj::{Gd, GodotClass};
1616

@@ -113,7 +113,7 @@ macro_rules! signal_argument_desc {
113113
name: $name,
114114
ty: <<<$type as GodotConvert>::Via as GodotType>::Ffi as godot::sys::GodotFfi>::VARIANT_TYPE.variant_as_nil(),
115115
class_name: <<$type as GodotConvert>::Via as GodotType>::class_id(),
116-
exported: false,
116+
usage: PropertyUsageFlags::NONE,
117117
hint: PropertyHint::NONE,
118118
hint_string: String::new(),
119119
description: "",

rust-script/src/static_script_registry.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub struct RustScriptPropDesc {
8484
pub name: &'static str,
8585
pub ty: VariantType,
8686
pub class_name: ClassId,
87-
pub exported: bool,
87+
pub usage: PropertyUsageFlags,
8888
pub hint: PropertyHint,
8989
pub hint_string: String,
9090
pub description: &'static str,
@@ -96,11 +96,7 @@ impl RustScriptPropDesc {
9696
variant_type: self.ty,
9797
class_name: self.class_name,
9898
property_name: self.name,
99-
usage: if self.exported {
100-
(PropertyUsageFlags::EDITOR | PropertyUsageFlags::STORAGE).ord()
101-
} else {
102-
PropertyUsageFlags::NONE.ord()
103-
},
99+
usage: self.usage.ord(),
104100
hint: self.hint.ord(),
105101
hint_string: self.hint_string.clone(),
106102
description: self.description,

rust-script/tests/script_derive.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use godot::builtin::{Array, GString};
88
use godot::classes::{Node, Node3D};
9+
use godot::global::PropertyHint;
910
use godot::obj::{Gd, NewAlloc};
1011
use godot_rust_script::{
1112
godot_script_impl, CastToScript, Context, GodotScript, GodotScriptEnum, OnEditor, RsRef,
@@ -58,14 +59,15 @@ struct TestScript {
5859
#[export(range(min = 0.0, max = 10.0))]
5960
pub int_range: u32,
6061

61-
#[export]
62+
#[export(storage)]
6263
pub custom_enum: ScriptEnum,
6364

6465
#[export]
6566
pub script_ref_opt: Option<RsRef<TestScript>>,
6667

67-
#[export]
68+
#[export(custom(hint = PropertyHint::NODE_TYPE, hint_string = ""))]
6869
pub script_ref: OnEditor<RsRef<TestScript>>,
70+
6971
base: Gd<<Self as GodotScript>::Base>,
7072
}
7173

0 commit comments

Comments
 (0)