Skip to content

Commit

Permalink
Add module init; move symbols from macros + export
Browse files Browse the repository at this point in the history
  • Loading branch information
Bromeon committed Nov 3, 2021
1 parent c90d7b7 commit 60d50d2
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 304 deletions.
2 changes: 1 addition & 1 deletion gdnative-async/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use gdnative_bindings::Object;
use gdnative_core::object::SubClass;

use gdnative_core::core_types::{GodotError, Variant};
use gdnative_core::export::InitHandle;
use gdnative_core::export::{Instance, RefInstance};
use gdnative_core::init::InitHandle;
use gdnative_core::object::ownership::Shared;
use gdnative_core::object::TRef;

Expand Down
180 changes: 5 additions & 175 deletions gdnative-core/src/export/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ use std::ptr;
use crate::core_types::{GodotString, ToVariant, Variant};
use crate::export::method::*;
use crate::export::property::*;
use crate::export::{class_registry, emplace};
use crate::export::{user_data::UserData, NativeClass, NativeClassMethods};
use crate::object::{GodotObject, NewRef, RawObject, TRef};
use crate::export::NativeClass;
use crate::object::NewRef;
use crate::private::get_api;

//pub use self::method::{
Expand All @@ -65,180 +64,11 @@ pub trait Export: ToVariant {
fn export_info(hint: Option<Self::Hint>) -> ExportInfo;
}

/// A handle that can register new classes to the engine during initialization.
///
/// See [`godot_nativescript_init`](macro.godot_nativescript_init.html) and
/// [`godot_init`](macro.godot_init.html).
#[derive(Copy, Clone)]
pub struct InitHandle {
#[doc(hidden)]
handle: *mut libc::c_void,
}

impl InitHandle {
#[doc(hidden)]
#[inline]
pub unsafe fn new(handle: *mut libc::c_void) -> Self {
InitHandle { handle }
}

/// Registers a new class to the engine.
#[inline]
pub fn add_class<C>(self)
where
C: NativeClassMethods,
{
self.add_maybe_tool_class::<C>(false)
}

/// Registers a new tool class to the engine.
#[inline]
pub fn add_tool_class<C>(self)
where
C: NativeClassMethods,
{
self.add_maybe_tool_class::<C>(true)
}

#[inline]
fn add_maybe_tool_class<C>(self, is_tool: bool)
where
C: NativeClassMethods,
{
if !class_registry::register_class::<C>() {
panic!(
"`{type_name}` has already been registered",
type_name = std::any::type_name::<C>()
);
}
unsafe {
let class_name = CString::new(C::class_name()).unwrap();
let base_name = CString::new(C::Base::class_name()).unwrap();

let create = {
unsafe extern "C" fn constructor<C: NativeClass>(
this: *mut sys::godot_object,
_method_data: *mut libc::c_void,
) -> *mut libc::c_void {
use std::panic::{self, AssertUnwindSafe};

let this = match ptr::NonNull::new(this) {
Some(this) => this,
None => {
godot_error!(
"gdnative-core: error constructing {}: owner pointer is null",
C::class_name(),
);

return ptr::null_mut();
}
};

let owner = match RawObject::<C::Base>::try_from_sys_ref(this) {
Some(owner) => owner,
None => {
godot_error!(
"gdnative-core: error constructing {}: incompatible owner type, expecting {}",
C::class_name(),
C::Base::class_name(),
);
return ptr::null_mut();
}
};

let val = match panic::catch_unwind(AssertUnwindSafe(|| {
emplace::take()
.unwrap_or_else(|| C::init(TRef::new(C::Base::cast_ref(owner))))
})) {
Ok(val) => val,
Err(_) => {
godot_error!(
"gdnative-core: error constructing {}: constructor panicked",
C::class_name(),
);
return ptr::null_mut();
}
};

let wrapper = C::UserData::new(val);
C::UserData::into_user_data(wrapper) as *mut _
}

sys::godot_instance_create_func {
create_func: Some(constructor::<C>),
method_data: ptr::null_mut(),
free_func: None,
}
};

let destroy = {
unsafe extern "C" fn destructor<C: NativeClass>(
_this: *mut sys::godot_object,
_method_data: *mut libc::c_void,
user_data: *mut libc::c_void,
) {
if user_data.is_null() {
godot_error!(
"gdnative-core: user data pointer for {} is null (did the constructor fail?)",
C::class_name(),
);
return;
}

let wrapper = C::UserData::consume_user_data_unchecked(user_data);
drop(wrapper)
}

sys::godot_instance_destroy_func {
destroy_func: Some(destructor::<C>),
method_data: ptr::null_mut(),
free_func: None,
}
};

if is_tool {
(get_api().godot_nativescript_register_tool_class)(
self.handle as *mut _,
class_name.as_ptr() as *const _,
base_name.as_ptr() as *const _,
create,
destroy,
);
} else {
(get_api().godot_nativescript_register_class)(
self.handle as *mut _,
class_name.as_ptr() as *const _,
base_name.as_ptr() as *const _,
create,
destroy,
);
}

(get_api().godot_nativescript_set_type_tag)(
self.handle as *mut _,
class_name.as_ptr() as *const _,
crate::export::type_tag::create::<C>(),
);

let builder = ClassBuilder {
init_handle: self.handle,
class_name,
_marker: PhantomData,
};

C::register_properties(&builder);

// register methods
C::register(&builder);
}
}
}

#[derive(Debug)]
pub struct ClassBuilder<C> {
pub(super) init_handle: *mut libc::c_void,
pub(super) class_name: CString,
_marker: PhantomData<C>,
pub(crate) init_handle: *mut libc::c_void,
pub(crate) class_name: CString,
pub(crate) _marker: PhantomData<C>,
}

impl<C: NativeClass> ClassBuilder<C> {
Expand Down
12 changes: 6 additions & 6 deletions gdnative-core/src/export/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
#[macro_export]
macro_rules! godot_nativescript_init {
() => {
fn godot_nativescript_init_empty(_init: $crate::export::InitHandle) {}
fn godot_nativescript_init_empty(_init: $crate::init::InitHandle) {}
$crate::godot_nativescript_init!(godot_nativescript_init_empty);
};
($callback:ident) => {
$crate::godot_nativescript_init!($callback as godot_nativescript_init);
};
(_ as $fn_name:ident) => {
fn godot_nativescript_init_empty(_init: $crate::export::InitHandle) {}
fn godot_nativescript_init_empty(_init: $crate::init::InitHandle) {}
$crate::godot_nativescript_init!(godot_nativescript_init_empty as $fn_name);
};
($callback:ident as $fn_name:ident) => {
Expand All @@ -36,7 +36,7 @@ macro_rules! godot_nativescript_init {
}

let __result = ::std::panic::catch_unwind(|| {
$callback($crate::export::InitHandle::new(handle));
$callback($crate::init::InitHandle::new(handle));
});

if __result.is_err() {
Expand All @@ -63,9 +63,9 @@ macro_rules! godot_nativescript_init {
#[macro_export]
macro_rules! godot_init {
($callback:ident) => {
$crate::godot_gdnative_init!();
$crate::godot_nativescript_init!($callback);
$crate::godot_gdnative_terminate!();
$crate::init::godot_gdnative_init!();
$crate::init::godot_nativescript_init!($callback);
$crate::init::godot_gdnative_terminate!();
};
}

Expand Down
4 changes: 2 additions & 2 deletions gdnative-core/src/export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
//! out the [`core_types`][crate::core_types] and [`object`][crate::object] modules, respectively.
mod class;
mod emplace;
#[allow(clippy::module_inception)] // same name as this module; TODO rename or spill out
mod export;
#[allow(clippy::module_inception)] // same name as this module; TODO rename or spill out
mod macros;
mod method;
mod property;

pub(crate) mod class_registry;
pub(crate) mod emplace;
pub(crate) mod type_tag;

pub use class::*;
Expand Down
96 changes: 96 additions & 0 deletions gdnative-core/src/init/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::core_types::GodotString;

/// Context for the [`godot_gdnative_init`][crate::init::godot_gdnative_init] callback.
pub struct InitializeInfo {
in_editor: bool,
active_library_path: GodotString,
options: *mut crate::sys::godot_gdnative_init_options,
}

impl InitializeInfo {
/// Returns true if the library is loaded in the Godot Editor.
#[inline]
pub fn in_editor(&self) -> bool {
self.in_editor
}

/// Returns a path to the library relative to the project.
///
/// Example: `res://../../target/debug/libhello_world.dylib`
#[inline]
pub fn active_library_path(&self) -> &GodotString {
&self.active_library_path
}

/// Internal interface.
///
/// # Safety
///
/// Will `panic!()` if options is NULL, UB if invalid.
#[inline]
#[doc(hidden)]
pub unsafe fn new(options: *mut crate::sys::godot_gdnative_init_options) -> Self {
assert!(!options.is_null(), "options were NULL");
let crate::sys::godot_gdnative_init_options {
in_editor,
active_library_path,
..
} = *options;

let active_library_path = GodotString::clone_from_sys(*active_library_path);

Self {
in_editor,
active_library_path,
options,
}
}

#[inline]
pub fn report_loading_error<T>(&self, message: T)
where
T: std::fmt::Display,
{
let crate::sys::godot_gdnative_init_options {
report_loading_error,
gd_native_library,
..
} = unsafe { *self.options };

if let Some(report_loading_error_fn) = report_loading_error {
// Add the trailing zero and convert Display => String
let message = format!("{}\0", message);

// Convert to FFI compatible string
let message = std::ffi::CStr::from_bytes_with_nul(message.as_bytes())
.expect("message should not have a NULL");

unsafe {
report_loading_error_fn(gd_native_library, message.as_ptr());
}
}
}
}

/// Context for the [`godot_gdnative_terminate`][crate::init::godot_gdnative_terminate] callback.
pub struct TerminateInfo {
in_editor: bool,
}

impl TerminateInfo {
#[inline]
#[doc(hidden)] // avoids clippy warning: unsafe function's docs miss `# Safety` section
pub unsafe fn new(options: *mut crate::sys::godot_gdnative_terminate_options) -> Self {
assert!(!options.is_null(), "options were NULL");

let crate::sys::godot_gdnative_terminate_options { in_editor } = *options;

Self { in_editor }
}

/// Returns `true` if the library is loaded in the Godot Editor.
#[inline]
pub fn in_editor(&self) -> bool {
self.in_editor
}
}
Loading

0 comments on commit 60d50d2

Please sign in to comment.