Skip to content

Commit e537bc7

Browse files
committed
feat: support engine enums in PhantomVar and implement Var/Export for bindings
1 parent 3416265 commit e537bc7

File tree

2 files changed

+66
-17
lines changed

2 files changed

+66
-17
lines changed

godot-codegen/src/generator/enums.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
use std::collections::HashSet;
1313

14+
use heck::ToPascalCase;
1415
use proc_macro2::TokenStream;
1516
use quote::{quote, ToTokens};
1617

@@ -45,6 +46,7 @@ pub fn make_enum_definition_with(
4546
// Things needed for the type definition
4647
let derives = enum_.derives();
4748
let enum_doc = make_enum_doc(enum_);
49+
let enum_hint_string = make_enum_hint_string(enum_);
4850
let name = &enum_.name;
4951

5052
// Values
@@ -105,9 +107,28 @@ pub fn make_enum_definition_with(
105107

106108
// Trait implementations.
107109
let engine_trait_impl = make_enum_engine_trait_impl(enum_, enum_bitmask.as_ref());
110+
let property_hint = if enum_.is_bitfield {
111+
quote! { crate::global::PropertyHint::FLAGS }
112+
} else {
113+
quote! { crate::global::PropertyHint::ENUM }
114+
};
108115
let index_enum_impl = make_enum_index_impl(enum_);
109116
let bitwise_impls = make_enum_bitwise_operators(enum_, enum_bitmask.as_ref());
110117

118+
let var_trait_set_property = if enum_.is_exhaustive {
119+
quote! {
120+
fn set_property(&mut self, value: Self::Via) {
121+
*self = <Self as #engine_trait>::from_ord(value);
122+
}
123+
}
124+
} else {
125+
quote! {
126+
fn set_property(&mut self, value: Self::Via) {
127+
self.ord = value;
128+
}
129+
}
130+
};
131+
111132
quote! {
112133
#engine_trait_impl
113134
#index_enum_impl
@@ -131,6 +152,23 @@ pub fn make_enum_definition_with(
131152
.ok_or_else(|| crate::meta::error::FromGodotError::InvalidEnum.into_error(via))
132153
}
133154
}
155+
156+
impl crate::registry::property::Var for #name {
157+
fn get_property(&self) -> Self::Via{
158+
<Self as #engine_trait>::ord(*self)
159+
}
160+
161+
#var_trait_set_property
162+
163+
fn var_hint() -> crate::meta::PropertyHintInfo{
164+
crate::meta::PropertyHintInfo{
165+
hint: #property_hint,
166+
hint_string: crate::builtin::GString::from(#enum_hint_string),
167+
}
168+
}
169+
}
170+
171+
impl crate::registry::property::Export for #name {}
134172
}
135173
});
136174

@@ -481,6 +519,17 @@ fn make_enum_doc(enum_: &Enum) -> Vec<String> {
481519

482520
docs
483521
}
522+
/// Returns the hint string for the given enum.
523+
///
524+
/// e.g.: "Left,Center,Right,Fill"
525+
fn make_enum_hint_string(enum_: &Enum) -> String {
526+
enum_
527+
.enumerators
528+
.iter()
529+
.map(|enumerator| enumerator.name.to_string().to_pascal_case())
530+
.collect::<Vec<String>>()
531+
.join(",")
532+
}
484533

485534
/// Creates a definition for `enumerator` of the type `enum_type`.
486535
///

godot-core/src/registry/property/phantom_var.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::fmt;
1010
use std::hash::{Hash, Hasher};
1111
use std::marker::PhantomData;
1212

13-
use crate::meta::{ClassId, GodotConvert, GodotType, PropertyHintInfo};
13+
use crate::meta::{ClassId, GodotConvert, PropertyHintInfo};
1414
use crate::registry::property::{Export, Var};
1515

1616
/// A zero-sized type for creating a property without a backing field, accessible only through custom getter/setter functions.
@@ -55,15 +55,15 @@ use crate::registry::property::{Export, Var};
5555
/// This field can now be accessed from GDScript as `banner.text`.
5656
// Bounds for T are somewhat un-idiomatically directly on the type, rather than impls.
5757
// This improves error messages in IDEs when using the type as a field.
58-
pub struct PhantomVar<T: GodotType + Var>(PhantomData<T>);
58+
pub struct PhantomVar<T: GodotConvert + Var>(PhantomData<T>);
5959

60-
impl<T: GodotType + Var> GodotConvert for PhantomVar<T> {
61-
type Via = T;
60+
impl<T: GodotConvert + Var> GodotConvert for PhantomVar<T> {
61+
type Via = <T as GodotConvert>::Via;
6262
}
6363

6464
// `PhantomVar` supports only part of `Var`, but it has to implement it, otherwise we cannot implement `Export` either.
6565
// The `GodotClass` derive macro should ensure that the `Var` implementation is not used.
66-
impl<T: GodotType + Var> Var for PhantomVar<T> {
66+
impl<T: GodotConvert + Var> Var for PhantomVar<T> {
6767
fn get_property(&self) -> Self::Via {
6868
unreachable!("code generated by GodotClass should call the custom getter")
6969
}
@@ -78,7 +78,7 @@ impl<T: GodotType + Var> Var for PhantomVar<T> {
7878
}
7979

8080
// Reuse values from `T`, if any.
81-
impl<T: GodotType + Var + Export> Export for PhantomVar<T> {
81+
impl<T: GodotConvert + Var + Export> Export for PhantomVar<T> {
8282
fn export_hint() -> PropertyHintInfo {
8383
<T as Export>::export_hint()
8484
}
@@ -88,7 +88,7 @@ impl<T: GodotType + Var + Export> Export for PhantomVar<T> {
8888
}
8989
}
9090

91-
impl<T: GodotType + Var> Default for PhantomVar<T> {
91+
impl<T: GodotConvert + Var> Default for PhantomVar<T> {
9292
fn default() -> Self {
9393
Self(Default::default())
9494
}
@@ -97,49 +97,49 @@ impl<T: GodotType + Var> Default for PhantomVar<T> {
9797
// Like `PhantomData` from the Rust standard library, `PhantomVar` implements many common traits like `Eq` and `Hash`
9898
// to allow these traits to be derived on containing structs as well.
9999

100-
impl<T: GodotType + Var> Clone for PhantomVar<T> {
100+
impl<T: GodotConvert + Var> Clone for PhantomVar<T> {
101101
fn clone(&self) -> Self {
102102
*self
103103
}
104104
}
105105

106-
impl<T: GodotType + Var> Copy for PhantomVar<T> {}
106+
impl<T: GodotConvert + Var> Copy for PhantomVar<T> {}
107107

108-
impl<T: GodotType + Var> fmt::Debug for PhantomVar<T> {
108+
impl<T: GodotConvert + Var> fmt::Debug for PhantomVar<T> {
109109
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110110
f.debug_tuple("PhantomVar").finish()
111111
}
112112
}
113113

114-
impl<T: GodotType + Var> PartialEq for PhantomVar<T> {
114+
impl<T: GodotConvert + Var> PartialEq for PhantomVar<T> {
115115
fn eq(&self, _other: &Self) -> bool {
116116
true
117117
}
118118
}
119119

120-
impl<T: GodotType + Var> Eq for PhantomVar<T> {}
120+
impl<T: GodotConvert + Var> Eq for PhantomVar<T> {}
121121

122-
impl<T: GodotType + Var> PartialOrd for PhantomVar<T> {
122+
impl<T: GodotConvert + Var> PartialOrd for PhantomVar<T> {
123123
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
124124
Some(self.cmp(other))
125125
}
126126
}
127127

128-
impl<T: GodotType + Var> Ord for PhantomVar<T> {
128+
impl<T: GodotConvert + Var> Ord for PhantomVar<T> {
129129
fn cmp(&self, _other: &Self) -> Ordering {
130130
Ordering::Equal
131131
}
132132
}
133133

134-
impl<T: GodotType + Var> Hash for PhantomVar<T> {
134+
impl<T: GodotConvert + Var> Hash for PhantomVar<T> {
135135
fn hash<H: Hasher>(&self, _state: &mut H) {}
136136
}
137137

138138
// SAFETY: This type contains no data.
139-
unsafe impl<T: GodotType + Var> Send for PhantomVar<T> {}
139+
unsafe impl<T: GodotConvert + Var> Send for PhantomVar<T> {}
140140

141141
// SAFETY: This type contains no data.
142-
unsafe impl<T: GodotType + Var> Sync for PhantomVar<T> {}
142+
unsafe impl<T: GodotConvert + Var> Sync for PhantomVar<T> {}
143143

144144
/// This type exists only as a place to add `compile_fail` doctests for `PhantomVar`, which do not need to be in the public documentation.
145145
///

0 commit comments

Comments
 (0)