Skip to content

Commit b8f6f15

Browse files
authored
Merge pull request #552 from godot-rust/qol/bounds
Split `GodotClass`/`Bounds`, `UserClass` -> `NewGd`/`NewAlloc`
2 parents 5effee3 + 735cfd0 commit b8f6f15

34 files changed

+643
-469
lines changed

examples/dodge-the-creeps/rust/src/main_scene.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl Main {
119119
impl INode for Main {
120120
fn init(base: Base<Node>) -> Self {
121121
Main {
122-
mob_scene: PackedScene::new(),
122+
mob_scene: PackedScene::new_gd(),
123123
score: 0,
124124
base,
125125
music: None,

godot-codegen/src/class_generator.rs

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ fn make_constructor_and_default(
452452
// Note: this could use class_name() but is not yet done due to upcoming lazy-load refactoring.
453453
//let class_name_obj = quote! { <Self as crate::obj::GodotClass>::class_name() };
454454

455-
let (constructor, godot_default_impl);
455+
let (constructor, has_godot_default_impl);
456456
if ctx.is_singleton(godot_class_name) {
457457
// Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
458458
// &'static Self would be possible, but we would lose the whole mutability information (even if that is best-effort and
@@ -468,43 +468,38 @@ fn make_constructor_and_default(
468468
}
469469
}
470470
};
471-
godot_default_impl = TokenStream::new();
471+
has_godot_default_impl = false;
472472
} else if !class.is_instantiable {
473473
// Abstract base classes or non-singleton classes without constructor
474474
constructor = TokenStream::new();
475-
godot_default_impl = TokenStream::new();
475+
has_godot_default_impl = false;
476476
} else if class.is_refcounted {
477477
// RefCounted, Resource, etc
478478
constructor = quote! {
479+
#[deprecated = "Replaced with `new_gd` in extension trait `NewGd`."]
479480
pub fn new() -> Gd<Self> {
480-
unsafe {
481-
let class_name = #godot_class_stringname;
482-
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
483-
Gd::from_obj_sys(object_ptr)
484-
}
481+
// <Self as crate::obj::NewGd>::new_gd()
482+
crate::obj::Gd::default()
485483
}
486484
};
487-
godot_default_impl = quote! {
485+
has_godot_default_impl = true;
486+
} else {
487+
// Manually managed classes: Object, Node etc
488+
constructor = quote! {};
489+
has_godot_default_impl = true;
490+
}
491+
492+
let godot_default_impl = if has_godot_default_impl {
493+
quote! {
488494
impl crate::obj::cap::GodotDefault for #class_name {
489495
fn __godot_default() -> crate::obj::Gd<Self> {
490-
Self::new()
496+
crate::engine::construct_engine_object::<Self>()
491497
}
492498
}
493-
};
499+
}
494500
} else {
495-
// Manually managed classes: Object, Node etc
496-
constructor = quote! {
497-
#[must_use]
498-
pub fn new_alloc() -> Gd<Self> {
499-
unsafe {
500-
let class_name = #godot_class_stringname;
501-
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
502-
Gd::from_obj_sys(object_ptr)
503-
}
504-
}
505-
};
506-
godot_default_impl = TokenStream::new();
507-
}
501+
TokenStream::new()
502+
};
508503

509504
(constructor, godot_default_impl)
510505
}
@@ -609,12 +604,18 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
609604
}
610605
};
611606

612-
let memory = if class_name.rust_ty == "Object" {
613-
ident("DynamicRefCount")
607+
let assoc_dyn_memory = if class_name.rust_ty == "Object" {
608+
ident("MemDynamic")
614609
} else if class.is_refcounted {
615-
ident("StaticRefCount")
610+
ident("MemRefCounted")
616611
} else {
617-
ident("ManualMemory")
612+
ident("MemManual")
613+
};
614+
615+
let assoc_memory = if class.is_refcounted {
616+
ident("MemRefCounted")
617+
} else {
618+
ident("MemManual")
618619
};
619620

620621
// mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub.
@@ -648,15 +649,19 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
648649
#internal_methods
649650
#constants
650651
}
651-
unsafe impl crate::obj::GodotClass for #class_name {
652+
impl crate::obj::GodotClass for #class_name {
652653
type Base = #base_ty;
653-
type Declarer = crate::obj::dom::EngineDomain;
654-
type Mem = crate::obj::mem::#memory;
655-
const INIT_LEVEL: Option<crate::init::InitLevel> = #init_level;
656654

657655
fn class_name() -> ClassName {
658656
ClassName::from_ascii_cstr(#class_name_cstr)
659657
}
658+
659+
const INIT_LEVEL: crate::init::InitLevel = #init_level;
660+
}
661+
unsafe impl crate::obj::Bounds for #class_name {
662+
type Memory = crate::obj::bounds::#assoc_memory;
663+
type DynMemory = crate::obj::bounds::#assoc_dyn_memory;
664+
type Declarer = crate::obj::bounds::DeclEngine;
660665
}
661666
impl crate::obj::EngineClass for #class_name {
662667
fn as_object_ptr(&self) -> sys::GDExtensionObjectPtr {

godot-codegen/src/util.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ impl ClassCodegenLevel {
6565

6666
pub fn to_init_level(self) -> TokenStream {
6767
match self {
68-
Self::Servers => quote! { Some(crate::init::InitLevel::Servers) },
69-
Self::Scene => quote! { Some(crate::init::InitLevel::Scene) },
70-
Self::Editor => quote! { Some(crate::init::InitLevel::Editor) },
68+
Self::Servers => quote! { crate::init::InitLevel::Servers },
69+
Self::Scene => quote! { crate::init::InitLevel::Scene },
70+
Self::Editor => quote! { crate::init::InitLevel::Editor },
7171
}
7272
}
7373
}

godot-core/src/builder/method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ macro_rules! impl_code_method {
117117
118118
$(
119119
let $arg = <$Param as sys::GodotFfi>::from_sys(*args.offset(idx));
120-
// FIXME update refcount, e.g. Gd::ready() or T::Mem::maybe_inc_ref(&result);
120+
// FIXME update refcount, e.g. Gd::ready() or T::DynMemory::maybe_inc_ref(&result);
121121
// possibly in from_sys() directly; what about from_sys_init() and from_{obj|str}_sys()?
122122
idx += 1;
123123
)*

godot-core/src/builtin/array.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use godot_ffi as sys;
99

1010
use crate::builtin::*;
11-
use crate::obj::Share;
1211
use crate::property::{Export, Property, PropertyHintInfo, TypeStringHint};
1312
use std::fmt;
1413
use std::marker::PhantomData;
@@ -718,12 +717,6 @@ impl<T: GodotType> Clone for Array<T> {
718717
}
719718
}
720719

721-
impl<T: GodotType> Share for Array<T> {
722-
fn share(&self) -> Self {
723-
self.clone()
724-
}
725-
}
726-
727720
impl<T: GodotType + TypeStringHint> TypeStringHint for Array<T> {
728721
fn type_string() -> String {
729722
format!("{}:{}", VariantType::Array as i32, T::type_string())

godot-core/src/builtin/callable.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use godot_ffi as sys;
1010
use crate::builtin::meta::{impl_godot_as_self, GodotType, ToGodot};
1111
use crate::builtin::{inner, StringName, Variant, VariantArray};
1212
use crate::engine::Object;
13-
use crate::obj::mem::Memory;
13+
use crate::obj::bounds::DynMemory;
14+
use crate::obj::Bounds;
1415
use crate::obj::{Gd, GodotClass, InstanceId};
1516
use std::{fmt, ptr};
1617
use sys::{ffi_methods, GodotFfi};
@@ -202,7 +203,7 @@ impl Callable {
202203
// Increment refcount because we're getting a reference, and `InnerCallable::get_object` doesn't
203204
// increment the refcount.
204205
self.as_inner().get_object().map(|object| {
205-
<Object as GodotClass>::Mem::maybe_inc_ref(&object.raw);
206+
<Object as Bounds>::DynMemory::maybe_inc_ref(&object.raw);
206207
object
207208
})
208209
}

godot-core/src/builtin/dictionary.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use godot_ffi as sys;
99

1010
use crate::builtin::meta::{FromGodot, ToGodot};
1111
use crate::builtin::{inner, Variant};
12-
use crate::obj::Share;
1312
use crate::property::{Export, Property, PropertyHintInfo, TypeStringHint};
1413
use std::fmt;
1514
use std::marker::PhantomData;
@@ -340,12 +339,6 @@ impl Clone for Dictionary {
340339
}
341340
}
342341

343-
impl Share for Dictionary {
344-
fn share(&self) -> Self {
345-
self.clone()
346-
}
347-
}
348-
349342
impl Property for Dictionary {
350343
type Intermediate = Self;
351344

godot-core/src/builtin/meta/class_name.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ pub struct ClassName {
3333
}
3434

3535
impl ClassName {
36-
#[doc(hidden)]
36+
/// Construct from a null-terminated ASCII string.
37+
///
38+
/// # Panics
39+
/// If the string is not null-terminated or contains internal null bytes.
3740
pub fn from_ascii_cstr(bytes: &'static [u8]) -> Self {
3841
assert!(bytes.is_ascii(), "string must be ASCII"); // only half of u8 range
3942
let c_str = CStr::from_bytes_with_nul(bytes).expect("string must be null-terminated");

godot-core/src/engine/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
//! Godot engine classes and methods.
99
1010
use crate::builtin::{GString, NodePath};
11-
use crate::obj::dom::EngineDomain;
12-
use crate::obj::{Gd, GodotClass, Inherits, InstanceId};
11+
use crate::obj::{bounds, Bounds, Gd, GodotClass, Inherits, InstanceId};
1312
use std::collections::HashSet;
1413

1514
// Re-exports of generated symbols
@@ -115,7 +114,7 @@ impl NodeExt for Node {
115114

116115
impl<U> NodeExt for Gd<U>
117116
where
118-
U: GodotClass<Declarer = EngineDomain> + Inherits<Node>,
117+
U: Bounds<Declarer = bounds::DeclEngine> + Inherits<Node>,
119118
{
120119
fn try_get_node_as<T>(&self, path: impl Into<NodePath>) -> Option<Gd<T>>
121120
where
@@ -161,8 +160,16 @@ pub(crate) fn object_ptr_from_id(instance_id: InstanceId) -> sys::GDExtensionObj
161160
unsafe { sys::interface_fn!(object_get_instance_from_id)(instance_id.to_u64()) }
162161
}
163162

164-
// ----------------------------------------------------------------------------------------------------------------------------------------------
165-
// Implementation of this file
163+
pub(crate) fn construct_engine_object<T>() -> Gd<T>
164+
where
165+
T: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
166+
{
167+
// SAFETY: adhere to Godot API; valid class name and returned pointer is an object.
168+
unsafe {
169+
let object_ptr = sys::interface_fn!(classdb_construct_object)(T::class_name().string_sys());
170+
Gd::from_obj_sys(object_ptr)
171+
}
172+
}
166173

167174
pub(crate) fn ensure_object_alive(
168175
instance_id: InstanceId,
@@ -203,6 +210,9 @@ pub(crate) fn ensure_object_inherits(
203210
)
204211
}
205212

213+
// ----------------------------------------------------------------------------------------------------------------------------------------------
214+
// Implementation of this file
215+
206216
/// Checks if `derived` inherits from `base`, using a cache for _successful_ queries.
207217
#[cfg(debug_assertions)]
208218
fn is_derived_base_cached(derived: ClassName, base: ClassName) -> bool {

0 commit comments

Comments
 (0)