Skip to content

Commit 5b3da95

Browse files
committed
feat(derive): add ExportEnum
currently the implementaion is dirty. I will refactor it after verifying it can work.
1 parent 4f7f43b commit 5b3da95

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

gdnative-derive/src/export_enum.rs

+80
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

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use proc_macro::TokenStream;
99
use proc_macro2::TokenStream as TokenStream2;
1010
use syn::{AttributeArgs, DeriveInput, ItemFn, ItemImpl};
1111

12+
mod export_enum;
1213
mod extend_bounds;
1314
mod methods;
1415
mod native_script;
@@ -482,6 +483,15 @@ pub fn derive_from_varargs(input: TokenStream) -> TokenStream {
482483
}
483484
}
484485

486+
#[proc_macro_derive(ExportEnum)]
487+
pub fn derive_export_enum(input: TokenStream) -> TokenStream {
488+
let derive_input = syn::parse_macro_input!(input as syn::DeriveInput);
489+
match export_enum::derive_export_enum(&derive_input) {
490+
Ok(stream) => stream.into(),
491+
Err(err) => err.to_compile_error().into(),
492+
}
493+
}
494+
485495
/// Returns a standard header for derived implementations.
486496
///
487497
/// Adds the `automatically_derived` attribute and prevents common lints from triggering

0 commit comments

Comments
 (0)