Skip to content

Commit 8920adb

Browse files
committed
Add implement_godot_bounds! macro when not using #[derive(GodotClass)]
1 parent a7358ab commit 8920adb

File tree

4 files changed

+61
-5
lines changed

4 files changed

+61
-5
lines changed

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/obj/bounds.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,25 @@ pub(super) mod private {
6262

6363
/// Library-implemented trait to check bounds on `GodotClass` types.
6464
///
65-
/// See also [`bounds`](crate::obj::bounds) module documentation.
65+
/// See [`bounds`](crate::obj::bounds) module for how to use this for bounds checking.
66+
///
67+
/// <div class="warning">
68+
/// <strong>Never</strong> implement this trait manually.
69+
/// </div>
70+
///
71+
/// Most of the time, this trait is covered by [`#[derive(GodotClass)`](../bind/derive.GodotClass.html).
72+
/// If you implement `GodotClass` manually, use the [`implement_godot_bounds!`][crate::implement_godot_bounds] macro.
73+
///
74+
/// There are two reasons to avoid a hand-written `impl Bounds`:
75+
/// - The trait is `unsafe` and it is very easy to get internal bounds wrong. This will lead to immediate UB.
76+
/// - Apart from the documented members, the trait may have undocumented items that may be broken at any time and stand under no SemVer
77+
/// guarantees.
6678
///
6779
/// # Safety
6880
///
69-
/// Internal.
70-
/// You **must not** implement this trait yourself. [`#[derive(GodotClass)`](../bind/derive.GodotClass.html) will automatically do it.
81+
/// Internal. The library implements this trait and ensures safety.
7182
pub unsafe trait Bounds {
83+
/// Defines the memory strategy of the static type.
7284
type Memory: Memory;
7385

7486
/// Defines the memory strategy of the instance (at runtime).
@@ -79,9 +91,50 @@ pub(super) mod private {
7991
type Declarer: Declarer;
8092
}
8193

94+
/// Implements [`Bounds`] for a user-defined class.
95+
///
96+
/// This is only necessary if you do not use the proc-macro API.
97+
///
98+
/// Since `Bounds` is a supertrait of [`GodotClass`][crate::obj::GodotClass], you cannot accidentally forget to implement it.
99+
///
100+
/// # Example
101+
/// ```no_run
102+
/// use godot::prelude::*;
103+
/// use godot::obj::bounds::implement_godot_bounds;
104+
/// use godot::builtin::meta::ClassName;
105+
///
106+
/// struct MyClass {}
107+
///
108+
/// impl GodotClass for MyClass {
109+
/// type Base = Node;
110+
///
111+
/// # const INIT_LEVEL: Option<InitLevel> = None;
112+
/// fn class_name() -> ClassName {
113+
/// ClassName::from_ascii_cstr(b"MyClass\0")
114+
/// }
115+
/// }
116+
///
117+
/// implement_godot_bounds!(MyClass);
118+
#[macro_export]
119+
macro_rules! implement_godot_bounds {
120+
($UserClass:ty) => {
121+
// SAFETY: bounds are library-defined, dependent on base. User has no influence in selecting them -> macro is safe.
122+
unsafe impl $crate::obj::Bounds for $UserClass {
123+
type Memory = <<$UserClass as $crate::obj::GodotClass>::Base as $crate::obj::Bounds>::Memory;
124+
type DynMemory = <<$UserClass as $crate::obj::GodotClass>::Base as $crate::obj::Bounds>::DynMemory;
125+
type Declarer = $crate::obj::bounds::DeclUser;
126+
}
127+
};
128+
}
129+
82130
pub trait Sealed {}
83131
}
84132

133+
// ----------------------------------------------------------------------------------------------------------------------------------------------
134+
// Macro re-exports
135+
136+
pub use crate::implement_godot_bounds;
137+
85138
// ----------------------------------------------------------------------------------------------------------------------------------------------
86139
// Memory bounds
87140

godot-core/src/obj/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ pub use raw::*;
3030
pub use traits::*;
3131

3232
pub mod bounds;
33-
3433
pub use bounds::private::Bounds;
3534

3635
// Do not re-export rtti here.

godot-core/src/obj/traits.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl GodotClass for () {
6262
}
6363
}
6464

65+
/// Unit impl only exists to represent "no base", and is used for exactly one class: `Object`.
6566
unsafe impl Bounds for () {
6667
type Memory = bounds::MemManual;
6768
type DynMemory = bounds::MemManual;

0 commit comments

Comments
 (0)