Skip to content

Commit 89cbefc

Browse files
committed
feat(derive): add ExportEnum
currently the implementaion is dirty. I will refactor it after verifying it can work.
1 parent 0f558c6 commit 89cbefc

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

gdnative-derive/src/export_enum.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use proc_macro2::TokenStream as TokenStream2;
2+
use syn::DeriveInput;
3+
4+
pub(crate) fn derive_export_enum(input: &DeriveInput) -> syn::Result<TokenStream2> {
5+
let derived_enum = match &input.data {
6+
syn::Data::Enum(data) => data,
7+
_ => todo!("return error"),
8+
};
9+
10+
let to_variant_impl = impl_to_variant(&input.ident, derived_enum)?;
11+
let from_variant_impl = impl_from_variant(&input.ident, derived_enum)?;
12+
let export_impl = impl_export(&input.ident, derived_enum)?;
13+
let combined_impl = quote! {
14+
#to_variant_impl
15+
#from_variant_impl
16+
#export_impl
17+
};
18+
19+
Ok(combined_impl)
20+
}
21+
22+
fn impl_to_variant(enum_ty: &syn::Ident, _data: &syn::DataEnum) -> syn::Result<TokenStream2> {
23+
let impl_block = quote! {
24+
impl ::gdnative::core_types::ToVariant for #enum_ty {
25+
#[inline]
26+
fn to_variant(&self) -> ::gdnative::core_types::Variant {
27+
(*self as i64).to_variant()
28+
}
29+
}
30+
};
31+
32+
Ok(impl_block)
33+
}
34+
35+
fn impl_from_variant(enum_ty: &syn::Ident, data: &syn::DataEnum) -> syn::Result<TokenStream2> {
36+
// TODO: reject non-unit enum variant
37+
let as_int = quote! { n };
38+
let arms = data.variants.iter().map(|variant| {
39+
let ident = &variant.ident;
40+
quote! {
41+
if #as_int == #enum_ty::#ident as i64 {
42+
return Ok(#enum_ty::#ident);
43+
}
44+
}
45+
});
46+
47+
let impl_block = quote! {
48+
impl ::gdnative::core_types::FromVariant for #enum_ty {
49+
#[inline]
50+
fn from_variant(variant: &::gdnative::core_types::Variant) -> Result<Self, ::gdnative::core_types::FromVariantError> {
51+
let #as_int = variant.try_to::<i64>()?;
52+
#(#arms)*
53+
54+
panic!()
55+
}
56+
}
57+
};
58+
59+
Ok(impl_block)
60+
}
61+
62+
fn impl_export(enum_ty: &syn::Ident, _data: &syn::DataEnum) -> syn::Result<TokenStream2> {
63+
let impl_block = quote! {
64+
impl ::gdnative::export::Export for #enum_ty {
65+
type Hint = ::gdnative::export::hint::IntHint<i64>;
66+
#[inline]
67+
fn export_info(hint: Option<Self::Hint>) -> ::gdnative::export::ExportInfo {
68+
if let Some(hint) = hint {
69+
if matches!(hint, ::gdnative::export::hint::IntHint::<i64>::Enum(_)) {
70+
return hint.export_info();
71+
}
72+
}
73+
74+
::gdnative::export::ExportInfo::new(::gdnative::core_types::VariantType::I64)
75+
}
76+
}
77+
};
78+
79+
Ok(impl_block)
80+
}

gdnative-derive/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ use proc_macro2::TokenStream as TokenStream2;
1010
use quote::ToTokens;
1111
use syn::{parse::Parser, AttributeArgs, DeriveInput, ItemFn, ItemImpl, ItemType};
1212

13+
<<<<<<< HEAD
1314
mod init;
15+
=======
16+
mod export_enum;
17+
mod extend_bounds;
18+
>>>>>>> feat(derive): add `ExportEnum`
1419
mod methods;
1520
mod native_script;
1621
mod profiled;
@@ -663,6 +668,15 @@ pub fn godot_wrap_method(input: TokenStream) -> TokenStream {
663668
}
664669
}
665670

671+
#[proc_macro_derive(ExportEnum)]
672+
pub fn derive_export_enum(input: TokenStream) -> TokenStream {
673+
let derive_input = syn::parse_macro_input!(input as syn::DeriveInput);
674+
match export_enum::derive_export_enum(&derive_input) {
675+
Ok(stream) => stream.into(),
676+
Err(err) => err.to_compile_error().into(),
677+
}
678+
}
679+
666680
/// Returns a standard header for derived implementations.
667681
///
668682
/// Adds the `automatically_derived` attribute and prevents common lints from triggering

0 commit comments

Comments
 (0)