Skip to content

Commit b9417dc

Browse files
committed
Allow #[register_with] for #[monomorphize]
1 parent a85f1ee commit b9417dc

File tree

5 files changed

+108
-7
lines changed

5 files changed

+108
-7
lines changed

gdnative-core/src/export/class.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,20 @@ pub trait NativeClass: Sized + 'static {
9999

100100
/// A NativeScript "class" that is statically named. [`NativeClass`] types that implement this
101101
/// trait can be registered using [`InitHandle::add_class`].
102+
///
103+
/// This trait will be renamed to [`Monomorphized`] in a future version since its purpose has
104+
/// grown beyond simply providing a static type name.
102105
pub trait StaticallyNamed: NativeClass {
103106
/// The name of the class.
104107
///
105108
/// This name must be unique for the dynamic library. For generic or library code where this
106109
/// is hard to satisfy, consider using [`InitHandle::add_class_as`] to provide a name
107110
/// at registration time instead.
108111
const CLASS_NAME: &'static str;
112+
113+
/// Function that registers methods specific to this monomorphization.
114+
#[inline]
115+
fn nativeclass_register_monomorphized(_builder: &ClassBuilder<Self>) {}
109116
}
110117

111118
/// Trait used to provide information of Godot-exposed methods of a script class.

gdnative-core/src/init/init_handle.rs

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,19 @@ impl InitHandle {
3434
where
3535
C: NativeClassMethods + StaticallyNamed,
3636
{
37-
self.add_maybe_tool_class_as::<C>(Cow::Borrowed(C::CLASS_NAME), false)
37+
self.add_class_with::<C>(|_| {})
38+
}
39+
40+
/// Registers a new class to the engine.
41+
#[inline]
42+
pub fn add_class_with<C>(self, f: impl FnOnce(&ClassBuilder<C>))
43+
where
44+
C: NativeClassMethods + StaticallyNamed,
45+
{
46+
self.add_maybe_tool_class_as_with::<C>(Cow::Borrowed(C::CLASS_NAME), false, |builder| {
47+
C::nativeclass_register_monomorphized(builder);
48+
f(builder);
49+
})
3850
}
3951

4052
/// Registers a new tool class to the engine.
@@ -43,7 +55,19 @@ impl InitHandle {
4355
where
4456
C: NativeClassMethods + StaticallyNamed,
4557
{
46-
self.add_maybe_tool_class_as::<C>(Cow::Borrowed(C::CLASS_NAME), true)
58+
self.add_tool_class_with::<C>(|_| {})
59+
}
60+
61+
/// Registers a new tool class to the engine.
62+
#[inline]
63+
pub fn add_tool_class_with<C>(self, f: impl FnOnce(&ClassBuilder<C>))
64+
where
65+
C: NativeClassMethods + StaticallyNamed,
66+
{
67+
self.add_maybe_tool_class_as_with::<C>(Cow::Borrowed(C::CLASS_NAME), true, |builder| {
68+
C::nativeclass_register_monomorphized(builder);
69+
f(builder);
70+
})
4771
}
4872

4973
/// Registers a new class to the engine
@@ -55,7 +79,19 @@ impl InitHandle {
5579
where
5680
C: NativeClassMethods,
5781
{
58-
self.add_maybe_tool_class_as::<C>(Cow::Owned(name), false)
82+
self.add_class_as_with::<C>(name, |_| {})
83+
}
84+
85+
/// Registers a new class to the engine
86+
///
87+
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
88+
/// name provided at registration.
89+
#[inline]
90+
pub fn add_class_as_with<C>(self, name: String, f: impl FnOnce(&ClassBuilder<C>))
91+
where
92+
C: NativeClassMethods,
93+
{
94+
self.add_maybe_tool_class_as_with::<C>(Cow::Owned(name), false, f)
5995
}
6096

6197
/// Registers a new tool class to the engine
@@ -67,13 +103,29 @@ impl InitHandle {
67103
where
68104
C: NativeClassMethods,
69105
{
70-
self.add_maybe_tool_class_as::<C>(Cow::Owned(name), true)
106+
self.add_tool_class_as_with::<C>(name, |_| {})
71107
}
72108

109+
/// Registers a new tool class to the engine
110+
///
111+
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
112+
/// name provided at registration.
73113
#[inline]
74-
fn add_maybe_tool_class_as<C>(self, name: Cow<'static, str>, is_tool: bool)
114+
pub fn add_tool_class_as_with<C>(self, name: String, f: impl FnOnce(&ClassBuilder<C>))
75115
where
76116
C: NativeClassMethods,
117+
{
118+
self.add_maybe_tool_class_as_with::<C>(Cow::Owned(name), true, f)
119+
}
120+
121+
#[inline]
122+
fn add_maybe_tool_class_as_with<C>(
123+
self,
124+
name: Cow<'static, str>,
125+
is_tool: bool,
126+
f: impl FnOnce(&ClassBuilder<C>),
127+
) where
128+
C: NativeClassMethods,
77129
{
78130
let c_class_name = CString::new(&*name).unwrap();
79131

@@ -202,6 +254,8 @@ impl InitHandle {
202254

203255
// register methods
204256
C::nativeclass_register(&builder);
257+
258+
f(&builder);
205259
}
206260
}
207261
}

gdnative-derive/src/native_script/mod.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ fn parse_derive_input(input: &DeriveInput) -> Result<DeriveData, syn::Error> {
353353

354354
pub(crate) fn derive_monomorphize(
355355
args: AttributeArgs,
356-
item_type: ItemType,
356+
mut item_type: ItemType,
357357
) -> Result<TokenStream2, syn::Error> {
358358
if let Some(arg) = args.first() {
359359
return Err(syn::Error::new(
@@ -367,12 +367,32 @@ pub(crate) fn derive_monomorphize(
367367
let name = &item_type.ident;
368368
let name_str = name.to_string();
369369

370+
let register_callback = item_type
371+
.attrs
372+
.iter()
373+
.find(|a| a.path.is_ident("register_with"))
374+
.map(|attr| attr.parse_args::<Path>())
375+
.transpose()?
376+
.map(|path| {
377+
quote! {
378+
#path(__builder);
379+
}
380+
});
381+
382+
item_type
383+
.attrs
384+
.retain(|attr| !attr.path.is_ident("register_with"));
385+
370386
Ok(quote! {
371387
#item_type
372388

373389
#derived
374390
impl #gdnative_core::export::StaticallyNamed for #name {
375391
const CLASS_NAME: &'static str = #name_str;
392+
393+
fn nativeclass_register_monomorphized(__builder: &#gdnative_core::export::ClassBuilder<#name>) {
394+
#register_callback
395+
}
376396
}
377397

378398
#derived

test/project/main.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ func _test_generic_class():
190190
var status = true
191191

192192
status = status && int_ops.add(1, 2) == 3
193+
status = status && int_ops.sub(3, 2) == 1
193194
status = status && str_ops.add("foo", "bar") == "foobar"
194195

195196
if !status:

test/src/test_generic_class.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{marker::PhantomData, ops::Add};
1+
use std::{marker::PhantomData, ops::Add, ops::Sub};
22

33
use gdnative::prelude::*;
44

@@ -40,8 +40,27 @@ where
4040
}
4141
}
4242

43+
#[methods(mixin = "SubMixin")]
44+
impl<T> GenericOps<T>
45+
where
46+
T: FromVariant + ToVariant + Sub<Output = T> + 'static,
47+
{
48+
#[method]
49+
fn sub(&self, a: T, b: T) -> T {
50+
a - b
51+
}
52+
}
53+
4354
#[gdnative::derive::monomorphize]
55+
#[register_with(register_sub)]
4456
type IntOps = GenericOps<i32>;
4557

4658
#[gdnative::derive::monomorphize]
4759
type StrOps = GenericOps<GodotString>;
60+
61+
fn register_sub<T>(builder: &ClassBuilder<GenericOps<T>>)
62+
where
63+
T: FromVariant + ToVariant + Sub<Output = T> + 'static,
64+
{
65+
builder.mixin::<SubMixin>();
66+
}

0 commit comments

Comments
 (0)