Skip to content

Commit

Permalink
Merge pull request #27 from godot-rust/feature/api-string-names
Browse files Browse the repository at this point in the history
GDExtension catch-up: class registration via `StringName`
  • Loading branch information
Bromeon authored Nov 20, 2022
2 parents 847d1f4 + 098e59b commit c348694
Show file tree
Hide file tree
Showing 28 changed files with 1,129 additions and 458 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/minimal-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ name: Minimal CI

on:
push:
branches:
- master
pull_request:
# branches:
# - master
Expand Down
535 changes: 535 additions & 0 deletions gdext-class/src/obj/gd.rs

Large diffs are not rendered by default.

126 changes: 71 additions & 55 deletions godot-codegen/input/gdnative_interface.h

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions godot-codegen/src/central_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {

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

#[doc(hidden)]
pub fn to_ord(self) -> crate::GDNativeVariantType {
pub fn sys(self) -> crate::GDNativeVariantType {
self as _
}
}
Expand All @@ -155,7 +155,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {

impl VariantOperator {
#[doc(hidden)]
pub fn from_ord(enumerator: crate::GDNativeVariantOperator) -> Self {
pub fn from_sys(enumerator: crate::GDNativeVariantOperator) -> Self {
match enumerator {
#(
#variant_op_enumerators_ord => Self::#variant_op_enumerators_pascal,
Expand All @@ -165,7 +165,7 @@ fn make_sys_code(central_items: &CentralItems) -> String {
}

#[doc(hidden)]
pub fn to_ord(self) -> crate::GDNativeVariantOperator {
pub fn sys(self) -> crate::GDNativeVariantOperator {
self as _
}
}
Expand Down
48 changes: 30 additions & 18 deletions godot-codegen/src/class_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

//! Generates a file for each Godot class

use proc_macro2::TokenStream;
use proc_macro2::{Literal, TokenStream};
use quote::{format_ident, quote};
use std::path::{Path, PathBuf};

use crate::api_parser::*;
use crate::util::{c_str, ident, safe_ident, strlit, to_module_name, to_rust_type};
use crate::util::{ident, safe_ident, strlit, to_module_name, to_rust_type};
use crate::{special_cases, util, Context, GeneratedClass, GeneratedModule, RustTy};

pub(crate) fn generate_class_files(
Expand Down Expand Up @@ -59,7 +59,7 @@ pub(crate) fn generate_class_files(
out_files.push(out_path);
}

fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream) -> TokenStream {
fn make_constructor(class: &Class, ctx: &Context, class_name_str: &Literal) -> TokenStream {
if ctx.is_singleton(&class.name) {
// Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
// &'static Self would be possible, but we would lose the whole mutability information (even if that
Expand All @@ -69,7 +69,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
quote! {
pub fn singleton() -> Gd<Self> {
unsafe {
let object_ptr = sys::interface_fn!(global_get_singleton)(#class_name_cstr);
let class_name = StringName::from(#class_name_str);
let object_ptr = sys::interface_fn!(global_get_singleton)(class_name.string_sys());
Gd::from_obj_sys(object_ptr)
}
}
Expand All @@ -82,7 +83,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
quote! {
pub fn new() -> Gd<Self> {
unsafe {
let object_ptr = sys::interface_fn!(classdb_construct_object)(#class_name_cstr);
let class_name = StringName::from(#class_name_str);
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
//let instance = Self { object_ptr };
Gd::from_obj_sys(object_ptr)
}
Expand All @@ -94,7 +96,8 @@ fn make_constructor(class: &Class, ctx: &Context, class_name_cstr: TokenStream)
#[must_use]
pub fn new_alloc() -> Gd<Self> {
unsafe {
let object_ptr = sys::interface_fn!(classdb_construct_object)(#class_name_cstr);
let class_name = StringName::from(#class_name_str);
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
Gd::from_obj_sys(object_ptr)
}
}
Expand All @@ -114,9 +117,8 @@ fn make_class(class: &Class, ctx: &mut Context) -> GeneratedClass {

let name = ident(&class.name);
let name_str = strlit(&class.name);
let name_cstr = c_str(&class.name);

let constructor = make_constructor(class, ctx, name_cstr);
let constructor = make_constructor(class, ctx, &name_str);

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

let method_name = special_cases::maybe_renamed(class_name, &method.name);
let method_name_str = special_cases::maybe_renamed(class_name, &method.name);
/*if method.map_args(|args| args.is_empty()) {
// Getters (i.e. 0 arguments) will be stripped of their `get_` prefix, to conform to Rust convention
if let Some(remainder) = method_name.strip_prefix("get_") {
Expand All @@ -367,10 +369,7 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
}
}
}*/
let method_name = safe_ident(method_name);

let c_method_name = c_str(&method.name);
let c_class_name = c_str(class_name);
let method_name = safe_ident(method_name_str);
let hash = method.hash;

// TODO &mut safety
Expand All @@ -393,7 +392,13 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
quote! {
#vis fn #method_name( #receiver #(, #params )*, varargs: &[Variant]) #return_decl {
unsafe {
let method_bind = sys::interface_fn!(classdb_get_method_bind)(#c_class_name, #c_method_name, #hash);
let class_name = StringName::from(#class_name);
let method_name = StringName::from(#method_name_str);
let method_bind = sys::interface_fn!(classdb_get_method_bind)(
class_name.string_sys(),
method_name.string_sys(),
#hash
);
let call_fn = sys::interface_fn!(object_method_bind_call);

let explicit_args = [
Expand All @@ -414,7 +419,13 @@ fn make_method_definition(method: &Method, class_name: &str, ctx: &mut Context)
quote! {
#vis fn #method_name( #receiver, #( #params ),* ) #return_decl {
unsafe {
let method_bind = sys::interface_fn!(classdb_get_method_bind)(#c_class_name, #c_method_name, #hash);
let class_name = StringName::from(#class_name);
let method_name = StringName::from(#method_name_str);
let method_bind = sys::interface_fn!(classdb_get_method_bind)(
class_name.string_sys(),
method_name.string_sys(),
#hash
);
let call_fn = sys::interface_fn!(object_method_bind_ptrcall);

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

let function_name = safe_ident(&function.name);
let c_function_name = c_str(&function.name);
let function_name_str = &function.name;
let function_name = safe_ident(function_name_str);
let hash = function.hash;

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

quote! {
pub fn #function_name( #( #params ),* ) #return_decl {
let result = unsafe {
let call_fn = sys::interface_fn!(variant_get_ptr_utility_function)(#c_function_name, #hash);
let function_name = StringName::from(#function_name_str);
let call_fn = sys::interface_fn!(variant_get_ptr_utility_function)(function_name.string_sys(), #hash);
let call_fn = call_fn.unwrap_unchecked();

let args = [
Expand Down
8 changes: 0 additions & 8 deletions godot-codegen/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,6 @@ pub fn safe_ident(s: &str) -> Ident {
}
}

// Code duplicated between here and godot-macros
pub fn c_str(s: &str) -> TokenStream {
let s = Literal::string(&format!("{}\0", s));
quote! {
#s.as_ptr() as *const i8
}
}

pub fn strlit(s: &str) -> Literal {
Literal::string(s)
}
Expand Down
43 changes: 24 additions & 19 deletions godot-core/src/builtin/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@

#![macro_use]

macro_rules! impl_basic_trait_as_sys {
( Drop for $Type:ty => $gd_method:ident ) => {
impl Drop for $Type {
macro_rules! impl_builtin_traits_inner {
( Default for $Type:ty => $gd_method:ident ) => {
impl Default for $Type {
#[inline]
fn drop(&mut self) {
unsafe { (get_api().$gd_method)(self.sys_mut()) }
fn default() -> Self {
unsafe {
let mut gd_val = sys::$GdType::default();
(sys::method_table().$gd_method)(&mut gd_val);
<$Type>::from_sys(gd_val)
}
}
}
};
Expand All @@ -21,22 +25,23 @@ macro_rules! impl_basic_trait_as_sys {
#[inline]
fn clone(&self) -> Self {
unsafe {
let mut result = sys::$GdType::default();
(get_api().$gd_method)(&mut result, self.sys());
<$Type>::from_sys(result)
Self::from_sys_init(|self_ptr| {
let ctor = sys::method_table().$gd_method;
let args = [self.sys()];
ctor(self_ptr, args.as_ptr());
})
}
}
}
};

( Default for $Type:ty => $gd_method:ident ) => {
impl Default for $Type {
( Drop for $Type:ty => $gd_method:ident ) => {
impl Drop for $Type {
#[inline]
fn default() -> Self {
fn drop(&mut self) {
unsafe {
let mut gd_val = sys::$GdType::default();
(get_api().$gd_method)(&mut gd_val);
<$Type>::from_sys(gd_val)
let destructor = sys::method_table().$gd_method;
destructor(self.sys_mut());
}
}
}
Expand All @@ -58,7 +63,7 @@ macro_rules! impl_basic_trait_as_sys {
};

( Eq for $Type:ty => $gd_method:ident ) => {
impl_basic_trait_as_sys!(PartialEq for $Type => $gd_method);
impl_builtin_traits_inner!(PartialEq for $Type => $gd_method);
impl Eq for $Type {}
};

Expand Down Expand Up @@ -86,7 +91,7 @@ macro_rules! impl_basic_trait_as_sys {
};

( Ord for $Type:ty => $gd_method:ident ) => {
impl_basic_trait_as_sys!(PartialOrd for $Type => $gd_method);
impl_builtin_traits_inner!(PartialOrd for $Type => $gd_method);
impl Ord for $Type {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
Expand All @@ -96,16 +101,16 @@ macro_rules! impl_basic_trait_as_sys {
};
}

macro_rules! impl_traits_as_sys {
macro_rules! impl_builtin_traits {
(
for $Type:ty {
$( $Trait:ident => $gd_method:ident; )*
}
) => (
$(
impl_basic_trait_as_sys!(
impl_builtin_traits_inner! {
$Trait for $Type => $gd_method
);
}
)*
)
}
Expand Down
43 changes: 43 additions & 0 deletions godot-core/src/builtin/meta/class_name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use godot_ffi as sys;

use std::fmt::{Display, Formatter, Result as FmtResult};

use crate::builtin::*;
use crate::obj::GodotClass;

/// Utility to construct class names known at compile time.
/// Cannot be a function since the backing string must be retained.
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
pub struct ClassName {
backing: StringName,
}

impl ClassName {
pub fn new<T: GodotClass>() -> Self {
Self {
backing: StringName::from(T::CLASS_NAME),
}
}

pub fn from_static(string: &'static str) -> Self {
Self {
backing: StringName::from(string),
}
}

pub fn string_sys(&self) -> sys::GDNativeStringNamePtr {
self.backing.string_sys()
}
}

impl Display for ClassName {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
self.backing.fmt(f)
}
}
Loading

0 comments on commit c348694

Please sign in to comment.