Skip to content

Commit c348694

Browse files
authored
Merge pull request #27 from godot-rust/feature/api-string-names
GDExtension catch-up: class registration via `StringName`
2 parents 847d1f4 + 098e59b commit c348694

File tree

28 files changed

+1129
-458
lines changed

28 files changed

+1129
-458
lines changed

.github/workflows/minimal-ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ name: Minimal CI
1818

1919
on:
2020
push:
21+
branches:
22+
- master
2123
pull_request:
2224
# branches:
2325
# - master

gdext-class/src/obj/gd.rs

Lines changed: 535 additions & 0 deletions
Large diffs are not rendered by default.

godot-codegen/input/gdnative_interface.h

Lines changed: 71 additions & 55 deletions
Large diffs are not rendered by default.

godot-codegen/src/central_generator.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {
124124

125125
impl VariantType {
126126
#[doc(hidden)]
127-
pub fn from_ord(enumerator: crate::GDNativeVariantType) -> Self {
127+
pub fn from_sys(enumerator: crate::GDNativeVariantType) -> Self {
128128
// Annoying, but only stable alternative is transmute(), which dictates enum size
129129
match enumerator {
130130
0 => Self::Nil,
@@ -136,7 +136,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {
136136
}
137137

138138
#[doc(hidden)]
139-
pub fn to_ord(self) -> crate::GDNativeVariantType {
139+
pub fn sys(self) -> crate::GDNativeVariantType {
140140
self as _
141141
}
142142
}
@@ -155,7 +155,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {
155155

156156
impl VariantOperator {
157157
#[doc(hidden)]
158-
pub fn from_ord(enumerator: crate::GDNativeVariantOperator) -> Self {
158+
pub fn from_sys(enumerator: crate::GDNativeVariantOperator) -> Self {
159159
match enumerator {
160160
#(
161161
#variant_op_enumerators_ord => Self::#variant_op_enumerators_pascal,
@@ -165,7 +165,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {
165165
}
166166

167167
#[doc(hidden)]
168-
pub fn to_ord(self) -> crate::GDNativeVariantOperator {
168+
pub fn sys(self) -> crate::GDNativeVariantOperator {
169169
self as _
170170
}
171171
}

godot-codegen/src/class_generator.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
//! Generates a file for each Godot class
88
9-
use proc_macro2::TokenStream;
9+
use proc_macro2::{Literal, TokenStream};
1010
use quote::{format_ident, quote};
1111
use std::path::{Path, PathBuf};
1212

1313
use crate::api_parser::*;
14-
use crate::util::{c_str, ident, safe_ident, strlit, to_module_name, to_rust_type};
14+
use crate::util::{ident, safe_ident, strlit, to_module_name, to_rust_type};
1515
use crate::{special_cases, util, Context, GeneratedClass, GeneratedModule, RustTy};
1616

1717
pub(crate) fn generate_class_files(
@@ -59,7 +59,7 @@ pub(crate) fn generate_class_files(
5959
out_files.push(out_path);
6060
}
6161

62-
fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream) -> TokenStream {
62+
fn make_constructor(class: &Class, ctx: &Context, class_name_str: &Literal) -> TokenStream {
6363
if ctx.is_singleton(&class.name) {
6464
// Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
6565
// &'static Self would be possible, but we would lose the whole mutability information (even if that
@@ -69,7 +69,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
6969
quote! {
7070
pub fn singleton() -> Gd<Self> {
7171
unsafe {
72-
let object_ptr = sys::interface_fn!(global_get_singleton)(#class_name_cstr);
72+
let class_name = StringName::from(#class_name_str);
73+
let object_ptr = sys::interface_fn!(global_get_singleton)(class_name.string_sys());
7374
Gd::from_obj_sys(object_ptr)
7475
}
7576
}
@@ -82,7 +83,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
8283
quote! {
8384
pub fn new() -> Gd<Self> {
8485
unsafe {
85-
let object_ptr = sys::interface_fn!(classdb_construct_object)(#class_name_cstr);
86+
let class_name = StringName::from(#class_name_str);
87+
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
8688
//let instance = Self { object_ptr };
8789
Gd::from_obj_sys(object_ptr)
8890
}
@@ -94,7 +96,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
9496
#[must_use]
9597
pub fn new_alloc() -> Gd<Self> {
9698
unsafe {
97-
let object_ptr = sys::interface_fn!(classdb_construct_object)(#class_name_cstr);
99+
let class_name = StringName::from(#class_name_str);
100+
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
98101
Gd::from_obj_sys(object_ptr)
99102
}
100103
}
@@ -114,9 +117,8 @@ fn make_class(class: &Class, ctx: &mut Context) -> GeneratedClass {
114117

115118
let name = ident(&class.name);
116119
let name_str = strlit(&class.name);
117-
let name_cstr = c_str(&class.name);
118120

119-
let constructor = make_constructor(class, ctx, name_cstr);
121+
let constructor = make_constructor(class, ctx, &name_str);
120122

121123
let methods = make_methods(&class.methods, &class.name, ctx);
122124
let enums = make_enums(&class.enums, &class.name, ctx);
@@ -356,7 +358,7 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
356358
let is_varcall = method.is_vararg;
357359
let (params, arg_exprs) = make_params(&method.arguments, is_varcall, ctx);
358360

359-
let method_name = special_cases::maybe_renamed(class_name, &method.name);
361+
let method_name_str = special_cases::maybe_renamed(class_name, &method.name);
360362
/*if method.map_args(|args| args.is_empty()) {
361363
// Getters (i.e. 0 arguments) will be stripped of their `get_` prefix, to conform to Rust convention
362364
if let Some(remainder) = method_name.strip_prefix("get_") {
@@ -367,10 +369,7 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
367369
}
368370
}
369371
}*/
370-
let method_name = safe_ident(method_name);
371-
372-
let c_method_name = c_str(&method.name);
373-
let c_class_name = c_str(class_name);
372+
let method_name = safe_ident(method_name_str);
374373
let hash = method.hash;
375374

376375
// TODO &mut safety
@@ -393,7 +392,13 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
393392
quote! {
394393
#vis fn #method_name( #receiver #(, #params )*, varargs: &[Variant]) #return_decl {
395394
unsafe {
396-
let method_bind = sys::interface_fn!(classdb_get_method_bind)(#c_class_name, #c_method_name, #hash);
395+
let class_name = StringName::from(#class_name);
396+
let method_name = StringName::from(#method_name_str);
397+
let method_bind = sys::interface_fn!(classdb_get_method_bind)(
398+
class_name.string_sys(),
399+
method_name.string_sys(),
400+
#hash
401+
);
397402
let call_fn = sys::interface_fn!(object_method_bind_call);
398403

399404
let explicit_args = [
@@ -414,7 +419,13 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
414419
quote! {
415420
#vis fn #method_name( #receiver, #( #params ),* ) #return_decl {
416421
unsafe {
417-
let method_bind = sys::interface_fn!(classdb_get_method_bind)(#c_class_name, #c_method_name, #hash);
422+
let class_name = StringName::from(#class_name);
423+
let method_name = StringName::from(#method_name_str);
424+
let method_bind = sys::interface_fn!(classdb_get_method_bind)(
425+
class_name.string_sys(),
426+
method_name.string_sys(),
427+
#hash
428+
);
418429
let call_fn = sys::interface_fn!(object_method_bind_ptrcall);
419430

420431
let args = [
@@ -441,16 +452,17 @@ pub(crate) fn make_function_definition(
441452
let is_vararg = function.is_vararg;
442453
let (params, arg_exprs) = make_params(&function.arguments, is_vararg, ctx);
443454

444-
let function_name = safe_ident(&function.name);
445-
let c_function_name = c_str(&function.name);
455+
let function_name_str = &function.name;
456+
let function_name = safe_ident(function_name_str);
446457
let hash = function.hash;
447458

448459
let (return_decl, call) = make_utility_return(&function.return_type, ctx);
449460

450461
quote! {
451462
pub fn #function_name( #( #params ),* ) #return_decl {
452463
let result = unsafe {
453-
let call_fn = sys::interface_fn!(variant_get_ptr_utility_function)(#c_function_name, #hash);
464+
let function_name = StringName::from(#function_name_str);
465+
let call_fn = sys::interface_fn!(variant_get_ptr_utility_function)(function_name.string_sys(), #hash);
454466
let call_fn = call_fn.unwrap_unchecked();
455467

456468
let args = [

godot-codegen/src/util.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,6 @@ pub fn safe_ident(s: &str) -> Ident {
218218
}
219219
}
220220

221-
// Code duplicated between here and godot-macros
222-
pub fn c_str(s: &str) -> TokenStream {
223-
let s = Literal::string(&format!("{}\0", s));
224-
quote! {
225-
#s.as_ptr() as *const i8
226-
}
227-
}
228-
229221
pub fn strlit(s: &str) -> Literal {
230222
Literal::string(s)
231223
}

godot-core/src/builtin/macros.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66

77
#![macro_use]
88

9-
macro_rules! impl_basic_trait_as_sys {
10-
( Drop for $Type:ty => $gd_method:ident ) => {
11-
impl Drop for $Type {
9+
macro_rules! impl_builtin_traits_inner {
10+
( Default for $Type:ty => $gd_method:ident ) => {
11+
impl Default for $Type {
1212
#[inline]
13-
fn drop(&mut self) {
14-
unsafe { (get_api().$gd_method)(self.sys_mut()) }
13+
fn default() -> Self {
14+
unsafe {
15+
let mut gd_val = sys::$GdType::default();
16+
(sys::method_table().$gd_method)(&mut gd_val);
17+
<$Type>::from_sys(gd_val)
18+
}
1519
}
1620
}
1721
};
@@ -21,22 +25,23 @@ macro_rules! impl_basic_trait_as_sys {
2125
#[inline]
2226
fn clone(&self) -> Self {
2327
unsafe {
24-
let mut result = sys::$GdType::default();
25-
(get_api().$gd_method)(&mut result, self.sys());
26-
<$Type>::from_sys(result)
28+
Self::from_sys_init(|self_ptr| {
29+
let ctor = sys::method_table().$gd_method;
30+
let args = [self.sys()];
31+
ctor(self_ptr, args.as_ptr());
32+
})
2733
}
2834
}
2935
}
3036
};
3137

32-
( Default for $Type:ty => $gd_method:ident ) => {
33-
impl Default for $Type {
38+
( Drop for $Type:ty => $gd_method:ident ) => {
39+
impl Drop for $Type {
3440
#[inline]
35-
fn default() -> Self {
41+
fn drop(&mut self) {
3642
unsafe {
37-
let mut gd_val = sys::$GdType::default();
38-
(get_api().$gd_method)(&mut gd_val);
39-
<$Type>::from_sys(gd_val)
43+
let destructor = sys::method_table().$gd_method;
44+
destructor(self.sys_mut());
4045
}
4146
}
4247
}
@@ -58,7 +63,7 @@ macro_rules! impl_basic_trait_as_sys {
5863
};
5964

6065
( Eq for $Type:ty => $gd_method:ident ) => {
61-
impl_basic_trait_as_sys!(PartialEq for $Type => $gd_method);
66+
impl_builtin_traits_inner!(PartialEq for $Type => $gd_method);
6267
impl Eq for $Type {}
6368
};
6469

@@ -86,7 +91,7 @@ macro_rules! impl_basic_trait_as_sys {
8691
};
8792

8893
( Ord for $Type:ty => $gd_method:ident ) => {
89-
impl_basic_trait_as_sys!(PartialOrd for $Type => $gd_method);
94+
impl_builtin_traits_inner!(PartialOrd for $Type => $gd_method);
9095
impl Ord for $Type {
9196
#[inline]
9297
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
@@ -96,16 +101,16 @@ macro_rules! impl_basic_trait_as_sys {
96101
};
97102
}
98103

99-
macro_rules! impl_traits_as_sys {
104+
macro_rules! impl_builtin_traits {
100105
(
101106
for $Type:ty {
102107
$( $Trait:ident => $gd_method:ident; )*
103108
}
104109
) => (
105110
$(
106-
impl_basic_trait_as_sys!(
111+
impl_builtin_traits_inner! {
107112
$Trait for $Type => $gd_method
108-
);
113+
}
109114
)*
110115
)
111116
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
use godot_ffi as sys;
8+
9+
use std::fmt::{Display, Formatter, Result as FmtResult};
10+
11+
use crate::builtin::*;
12+
use crate::obj::GodotClass;
13+
14+
/// Utility to construct class names known at compile time.
15+
/// Cannot be a function since the backing string must be retained.
16+
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
17+
pub struct ClassName {
18+
backing: StringName,
19+
}
20+
21+
impl ClassName {
22+
pub fn new<T: GodotClass>() -> Self {
23+
Self {
24+
backing: StringName::from(T::CLASS_NAME),
25+
}
26+
}
27+
28+
pub fn from_static(string: &'static str) -> Self {
29+
Self {
30+
backing: StringName::from(string),
31+
}
32+
}
33+
34+
pub fn string_sys(&self) -> sys::GDNativeStringNamePtr {
35+
self.backing.string_sys()
36+
}
37+
}
38+
39+
impl Display for ClassName {
40+
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
41+
self.backing.fmt(f)
42+
}
43+
}

0 commit comments

Comments
 (0)