Skip to content

Commit e6df1bb

Browse files
committed
Add module init; move symbols from macros + export
1 parent 233b8d0 commit e6df1bb

File tree

15 files changed

+473
-452
lines changed

15 files changed

+473
-452
lines changed

gdnative-async/src/rt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use gdnative_bindings::Object;
44
use gdnative_core::object::SubClass;
55

66
use gdnative_core::core_types::{GodotError, Variant};
7-
use gdnative_core::export::InitHandle;
87
use gdnative_core::export::{Instance, RefInstance};
8+
use gdnative_core::init::InitHandle;
99
use gdnative_core::object::ownership::Shared;
1010
use gdnative_core::object::TRef;
1111

gdnative-core/src/export/class_builder.rs

Lines changed: 9 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -38,180 +38,10 @@ use std::marker::PhantomData;
3838
use std::ptr;
3939

4040
use crate::core_types::{GodotString, Variant};
41-
use crate::export::user_data::UserData;
4241
use crate::export::*;
43-
use crate::object::{GodotObject, NewRef, RawObject, TRef};
42+
use crate::object::NewRef;
4443
use crate::private::get_api;
4544

46-
/// A handle that can register new classes to the engine during initialization.
47-
///
48-
/// See [`godot_nativescript_init`](macro.godot_nativescript_init.html) and
49-
/// [`godot_init`](macro.godot_init.html).
50-
#[derive(Copy, Clone)]
51-
pub struct InitHandle {
52-
#[doc(hidden)]
53-
handle: *mut libc::c_void,
54-
}
55-
56-
impl InitHandle {
57-
#[doc(hidden)]
58-
#[inline]
59-
pub unsafe fn new(handle: *mut libc::c_void) -> Self {
60-
InitHandle { handle }
61-
}
62-
63-
/// Registers a new class to the engine.
64-
#[inline]
65-
pub fn add_class<C>(self)
66-
where
67-
C: NativeClassMethods,
68-
{
69-
self.add_maybe_tool_class::<C>(false)
70-
}
71-
72-
/// Registers a new tool class to the engine.
73-
#[inline]
74-
pub fn add_tool_class<C>(self)
75-
where
76-
C: NativeClassMethods,
77-
{
78-
self.add_maybe_tool_class::<C>(true)
79-
}
80-
81-
#[inline]
82-
fn add_maybe_tool_class<C>(self, is_tool: bool)
83-
where
84-
C: NativeClassMethods,
85-
{
86-
if !class_registry::register_class::<C>() {
87-
panic!(
88-
"`{type_name}` has already been registered",
89-
type_name = std::any::type_name::<C>()
90-
);
91-
}
92-
unsafe {
93-
let class_name = CString::new(C::class_name()).unwrap();
94-
let base_name = CString::new(C::Base::class_name()).unwrap();
95-
96-
let create = {
97-
unsafe extern "C" fn constructor<C: NativeClass>(
98-
this: *mut sys::godot_object,
99-
_method_data: *mut libc::c_void,
100-
) -> *mut libc::c_void {
101-
use std::panic::{self, AssertUnwindSafe};
102-
103-
let this = match ptr::NonNull::new(this) {
104-
Some(this) => this,
105-
None => {
106-
godot_error!(
107-
"gdnative-core: error constructing {}: owner pointer is null",
108-
C::class_name(),
109-
);
110-
111-
return ptr::null_mut();
112-
}
113-
};
114-
115-
let owner = match RawObject::<C::Base>::try_from_sys_ref(this) {
116-
Some(owner) => owner,
117-
None => {
118-
godot_error!(
119-
"gdnative-core: error constructing {}: incompatible owner type, expecting {}",
120-
C::class_name(),
121-
C::Base::class_name(),
122-
);
123-
return ptr::null_mut();
124-
}
125-
};
126-
127-
let val = match panic::catch_unwind(AssertUnwindSafe(|| {
128-
emplace::take()
129-
.unwrap_or_else(|| C::init(TRef::new(C::Base::cast_ref(owner))))
130-
})) {
131-
Ok(val) => val,
132-
Err(_) => {
133-
godot_error!(
134-
"gdnative-core: error constructing {}: constructor panicked",
135-
C::class_name(),
136-
);
137-
return ptr::null_mut();
138-
}
139-
};
140-
141-
let wrapper = C::UserData::new(val);
142-
C::UserData::into_user_data(wrapper) as *mut _
143-
}
144-
145-
sys::godot_instance_create_func {
146-
create_func: Some(constructor::<C>),
147-
method_data: ptr::null_mut(),
148-
free_func: None,
149-
}
150-
};
151-
152-
let destroy = {
153-
unsafe extern "C" fn destructor<C: NativeClass>(
154-
_this: *mut sys::godot_object,
155-
_method_data: *mut libc::c_void,
156-
user_data: *mut libc::c_void,
157-
) {
158-
if user_data.is_null() {
159-
godot_error!(
160-
"gdnative-core: user data pointer for {} is null (did the constructor fail?)",
161-
C::class_name(),
162-
);
163-
return;
164-
}
165-
166-
let wrapper = C::UserData::consume_user_data_unchecked(user_data);
167-
drop(wrapper)
168-
}
169-
170-
sys::godot_instance_destroy_func {
171-
destroy_func: Some(destructor::<C>),
172-
method_data: ptr::null_mut(),
173-
free_func: None,
174-
}
175-
};
176-
177-
if is_tool {
178-
(get_api().godot_nativescript_register_tool_class)(
179-
self.handle as *mut _,
180-
class_name.as_ptr() as *const _,
181-
base_name.as_ptr() as *const _,
182-
create,
183-
destroy,
184-
);
185-
} else {
186-
(get_api().godot_nativescript_register_class)(
187-
self.handle as *mut _,
188-
class_name.as_ptr() as *const _,
189-
base_name.as_ptr() as *const _,
190-
create,
191-
destroy,
192-
);
193-
}
194-
195-
(get_api().godot_nativescript_set_type_tag)(
196-
self.handle as *mut _,
197-
class_name.as_ptr() as *const _,
198-
crate::export::type_tag::create::<C>(),
199-
);
200-
201-
let builder = ClassBuilder {
202-
init_handle: self.handle,
203-
class_name,
204-
_marker: PhantomData,
205-
};
206-
207-
C::register_properties(&builder);
208-
209-
// register methods
210-
C::register(&builder);
211-
}
212-
}
213-
}
214-
21545
#[derive(Debug)]
21646
pub struct ClassBuilder<C> {
21747
pub(super) init_handle: *mut libc::c_void,
@@ -220,6 +50,14 @@ pub struct ClassBuilder<C> {
22050
}
22151

22252
impl<C: NativeClass> ClassBuilder<C> {
53+
pub(crate) fn new(init_handle: *mut libc::c_void, class_name: CString) -> Self {
54+
Self {
55+
init_handle,
56+
class_name,
57+
_marker: PhantomData,
58+
}
59+
}
60+
22361
#[inline]
22462
#[deprecated(note = "Unsafe registration is deprecated. Use `build_method` instead.")]
22563
pub fn add_method_advanced(&self, method: ScriptMethod) {

gdnative-core/src/export/macros.rs

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,5 @@
11
#![macro_use]
22

3-
/// Declare the API endpoint to initialize export classes on startup.
4-
///
5-
/// By default this declares an extern function named `godot_nativescript_init`.
6-
/// This can be overridden, for example:
7-
///
8-
/// ```ignore
9-
/// // Declares an extern function named custom_nativescript_init instead of
10-
/// // godot_nativescript_init.
11-
/// godot_gdnative_terminate!(my_registration_callback as custom_nativescript_init);
12-
/// ```
13-
///
14-
/// Overriding the default entry point names can be useful if several gdnative
15-
/// libraries are linked statically to avoid name clashes.
16-
#[macro_export]
17-
macro_rules! godot_nativescript_init {
18-
() => {
19-
fn godot_nativescript_init_empty(_init: $crate::export::InitHandle) {}
20-
$crate::godot_nativescript_init!(godot_nativescript_init_empty);
21-
};
22-
($callback:ident) => {
23-
$crate::godot_nativescript_init!($callback as godot_nativescript_init);
24-
};
25-
(_ as $fn_name:ident) => {
26-
fn godot_nativescript_init_empty(_init: $crate::export::InitHandle) {}
27-
$crate::godot_nativescript_init!(godot_nativescript_init_empty as $fn_name);
28-
};
29-
($callback:ident as $fn_name:ident) => {
30-
#[no_mangle]
31-
#[doc(hidden)]
32-
#[allow(unused_unsafe)]
33-
pub unsafe extern "C" fn $fn_name(handle: *mut $crate::libc::c_void) {
34-
if !$crate::private::is_api_bound() {
35-
return;
36-
}
37-
38-
let __result = ::std::panic::catch_unwind(|| {
39-
$callback($crate::export::InitHandle::new(handle));
40-
});
41-
42-
if __result.is_err() {
43-
$crate::godot_error!("gdnative-core: nativescript_init callback panicked");
44-
}
45-
}
46-
};
47-
}
48-
49-
/// Declare all the API endpoints necessary to initialize a NativeScript library.
50-
///
51-
/// `godot_init!(init)` is a shorthand for:
52-
///
53-
/// ```ignore
54-
/// godot_gdnative_init!();
55-
/// godot_nativescript_init!(init);
56-
/// godot_gdnative_terminate!();
57-
/// ```
58-
///
59-
/// This declares three extern functions, named `godot_gdnative_init`,
60-
/// `godot_nativescript_init`, and `godot_gdnative_terminate`. If you need different prefixes
61-
/// to avoid name clashes when multiple GDNative libraries are linked statically, please use
62-
/// the respective macros directly.
63-
#[macro_export]
64-
macro_rules! godot_init {
65-
($callback:ident) => {
66-
$crate::godot_gdnative_init!();
67-
$crate::godot_nativescript_init!($callback);
68-
$crate::godot_gdnative_terminate!();
69-
};
70-
}
71-
723
#[doc(hidden)]
734
#[macro_export]
745
macro_rules! godot_wrap_method_parameter_count {

gdnative-core/src/export/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
1212
mod class;
1313
mod class_builder;
14-
mod emplace;
1514
mod macros;
1615
mod method;
1716
mod property;
1817

1918
pub(crate) mod class_registry;
19+
pub(crate) mod emplace;
2020
pub(crate) mod type_tag;
2121

2222
pub use class::*;

gdnative-core/src/init/info.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use crate::core_types::GodotString;
2+
3+
/// Context for the [`godot_gdnative_init`][crate::init::godot_gdnative_init] callback.
4+
pub struct InitializeInfo {
5+
in_editor: bool,
6+
active_library_path: GodotString,
7+
options: *mut crate::sys::godot_gdnative_init_options,
8+
}
9+
10+
impl InitializeInfo {
11+
/// Returns true if the library is loaded in the Godot Editor.
12+
#[inline]
13+
pub fn in_editor(&self) -> bool {
14+
self.in_editor
15+
}
16+
17+
/// Returns a path to the library relative to the project.
18+
///
19+
/// Example: `res://../../target/debug/libhello_world.dylib`
20+
#[inline]
21+
pub fn active_library_path(&self) -> &GodotString {
22+
&self.active_library_path
23+
}
24+
25+
/// Internal interface.
26+
///
27+
/// # Safety
28+
///
29+
/// Will `panic!()` if options is NULL, UB if invalid.
30+
#[inline]
31+
#[doc(hidden)]
32+
pub unsafe fn new(options: *mut crate::sys::godot_gdnative_init_options) -> Self {
33+
assert!(!options.is_null(), "options were NULL");
34+
let crate::sys::godot_gdnative_init_options {
35+
in_editor,
36+
active_library_path,
37+
..
38+
} = *options;
39+
40+
let active_library_path = GodotString::clone_from_sys(*active_library_path);
41+
42+
Self {
43+
in_editor,
44+
active_library_path,
45+
options,
46+
}
47+
}
48+
49+
#[inline]
50+
pub fn report_loading_error<T>(&self, message: T)
51+
where
52+
T: std::fmt::Display,
53+
{
54+
let crate::sys::godot_gdnative_init_options {
55+
report_loading_error,
56+
gd_native_library,
57+
..
58+
} = unsafe { *self.options };
59+
60+
if let Some(report_loading_error_fn) = report_loading_error {
61+
// Add the trailing zero and convert Display => String
62+
let message = format!("{}\0", message);
63+
64+
// Convert to FFI compatible string
65+
let message = std::ffi::CStr::from_bytes_with_nul(message.as_bytes())
66+
.expect("message should not have a NULL");
67+
68+
unsafe {
69+
report_loading_error_fn(gd_native_library, message.as_ptr());
70+
}
71+
}
72+
}
73+
}
74+
75+
/// Context for the [`godot_gdnative_terminate`][crate::init::godot_gdnative_terminate] callback.
76+
pub struct TerminateInfo {
77+
in_editor: bool,
78+
}
79+
80+
impl TerminateInfo {
81+
#[inline]
82+
#[doc(hidden)] // avoids clippy warning: unsafe function's docs miss `# Safety` section
83+
pub unsafe fn new(options: *mut crate::sys::godot_gdnative_terminate_options) -> Self {
84+
assert!(!options.is_null(), "options were NULL");
85+
86+
let crate::sys::godot_gdnative_terminate_options { in_editor } = *options;
87+
88+
Self { in_editor }
89+
}
90+
91+
/// Returns `true` if the library is loaded in the Godot Editor.
92+
#[inline]
93+
pub fn in_editor(&self) -> bool {
94+
self.in_editor
95+
}
96+
}

0 commit comments

Comments
 (0)