#![macro_use]
#[macro_export]
macro_rules! godot_gdnative_init {
() => {
fn godot_gdnative_init_empty(_options: *mut $crate::sys::godot_gdnative_init_options) {}
godot_gdnative_init!(godot_gdnative_init_empty);
};
(_ as $fn_name:ident) => {
fn godot_gdnative_init_empty(_options: *mut $crate::sys::godot_gdnative_init_options) {}
godot_gdnative_init!(godot_gdnative_init_empty as $fn_name);
};
($callback:ident) => {
godot_gdnative_init!($callback as godot_gdnative_init);
};
($callback:ident as $fn_name:ident) => {
#[no_mangle]
#[doc(hidden)]
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $fn_name(options: *mut $crate::sys::godot_gdnative_init_options) {
if !$crate::private::bind_api(options) {
return;
}
let __result = ::std::panic::catch_unwind(|| $callback(options));
if __result.is_err() {
godot_error!("gdnative-core: gdnative_init callback panicked");
}
}
};
}
#[macro_export]
macro_rules! godot_gdnative_terminate {
() => {
fn godot_gdnative_terminate_empty(
_options: *mut $crate::sys::godot_gdnative_terminate_options,
) {
}
godot_gdnative_terminate!(godot_gdnative_terminate_empty);
};
($callback:ident) => {
godot_gdnative_terminate!($callback as godot_gdnative_terminate);
};
(_ as $fn_name:ident) => {
fn godot_gdnative_terminate_empty(
_options: *mut $crate::sys::godot_gdnative_terminate_options,
) {
}
godot_gdnative_terminate!(godot_gdnative_terminate_empty as $fn_name);
};
($callback:ident as $fn_name:ident) => {
#[no_mangle]
#[doc(hidden)]
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $fn_name(
options: *mut $crate::sys::godot_gdnative_terminate_options,
) {
if !$crate::private::is_api_bound() {
return;
}
let __result = ::std::panic::catch_unwind(|| $callback(options));
if __result.is_err() {
godot_error!("gdnative-core: nativescript_init callback panicked");
}
$crate::private::cleanup_internal_state();
}
};
}
#[macro_export]
macro_rules! godot_nativescript_init {
() => {
fn godot_nativescript_init_empty(_init: $crate::init::InitHandle) {}
godot_nativescript_init!(godot_nativescript_init_empty);
};
($callback:ident) => {
godot_nativescript_init!($callback as godot_nativescript_init);
};
(_ as $fn_name:ident) => {
fn godot_nativescript_init_empty(_init: $crate::init::InitHandle) {}
godot_nativescript_init!(godot_nativescript_init_empty as $fn_name);
};
($callback:ident as $fn_name:ident) => {
#[no_mangle]
#[doc(hidden)]
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $fn_name(handle: *mut $crate::libc::c_void) {
if !$crate::private::is_api_bound() {
return;
}
let __result = ::std::panic::catch_unwind(|| {
$callback($crate::init::InitHandle::new(handle));
});
if __result.is_err() {
godot_error!("gdnative-core: nativescript_init callback panicked");
}
}
};
}
#[macro_export]
macro_rules! godot_print {
($($args:tt)*) => ({
let msg = format!($($args)*);
#[allow(unused_unsafe)]
unsafe {
let msg = $crate::GodotString::from_str(msg);
($crate::private::get_api().godot_print)(&msg.to_sys() as *const _);
}
});
}
#[macro_export]
macro_rules! godot_dbg {
() => {
$crate::godot_print!("[{}:{}]", ::std::file!(), ::std::line!());
};
($val:expr) => {
match $val {
tmp => {
$crate::godot_print!("[{}:{}] {} = {:#?}",
::std::file!(), ::std::line!(), ::std::stringify!($val), &tmp);
tmp
}
}
};
($val:expr,) => { $crate::godot_dbg!($val) };
($($val:expr),+ $(,)?) => {
($($crate::godot_dbg!($val)),+,)
};
}
#[macro_export]
macro_rules! godot_warn {
($($args:tt)*) => ({
let msg = format!($($args)*);
let line = line!();
let file = file!();
#[allow(unused_unsafe)]
unsafe {
let msg = ::std::ffi::CString::new(msg).unwrap();
let file = ::std::ffi::CString::new(file).unwrap();
let func = b"<native>\0";
($crate::private::get_api().godot_print_warning)(
msg.as_ptr() as *const _,
func.as_ptr() as *const _,
file.as_ptr() as *const _,
line as _,
);
}
})
}
#[macro_export]
macro_rules! godot_error {
($($args:tt)*) => ({
let msg = format!($($args)*);
let line = line!();
let file = file!();
#[allow(unused_unsafe)]
unsafe {
let msg = ::std::ffi::CString::new(msg).unwrap();
let file = ::std::ffi::CString::new(file).unwrap();
let func = b"<native>\0";
($crate::private::get_api().godot_print_error)(
msg.as_ptr() as *const _,
func.as_ptr() as *const _,
file.as_ptr() as *const _,
line as _,
);
}
})
}
macro_rules! impl_basic_trait {
(
Drop for $Type:ident as $GdType:ident : $gd_method:ident
) => {
impl Drop for $Type {
fn drop(&mut self) {
unsafe { (get_api().$gd_method)(&mut self.0) }
}
}
};
(
Clone for $Type:ident as $GdType:ident : $gd_method:ident
) => {
impl Clone for $Type {
fn clone(&self) -> Self {
unsafe {
let mut result = sys::$GdType::default();
(get_api().$gd_method)(&mut result, &self.0);
$Type(result)
}
}
}
};
(
Default for $Type:ident as $GdType:ident : $gd_method:ident
) => {
impl Default for $Type {
fn default() -> Self {
unsafe {
let mut gd_val = sys::$GdType::default();
(get_api().$gd_method)(&mut gd_val);
$Type(gd_val)
}
}
}
};
(
PartialEq for $Type:ident as $GdType:ident : $gd_method:ident
) => {
impl PartialEq for $Type {
fn eq(&self, other: &Self) -> bool {
unsafe { (get_api().$gd_method)(&self.0, &other.0) }
}
}
};
(
Eq for $Type:ident as $GdType:ident : $gd_method:ident
) => {
impl PartialEq for $Type {
fn eq(&self, other: &Self) -> bool {
unsafe { (get_api().$gd_method)(&self.0, &other.0) }
}
}
impl Eq for $Type {}
};
}
macro_rules! impl_basic_traits {
(
for $Type:ident as $GdType:ident {
$( $Trait:ident => $gd_method:ident; )*
}
) => (
$(
impl_basic_trait!(
$Trait for $Type as $GdType : $gd_method
);
)*
)
}
macro_rules! impl_common_method {
(
$(#[$attr:meta])*
pub fn new_ref(&self) -> $Type:ident : $gd_method:ident
) => {
$(#[$attr])*
pub fn new_ref(&self) -> $Type {
unsafe {
let mut result = Default::default();
(get_api().$gd_method)(&mut result, &self.0);
$Type(result)
}
}
};
}
macro_rules! impl_common_methods {
(
$(
$(#[$attr:meta])*
pub fn $name:ident(&self $(,$pname:ident : $pty:ty)*) -> $Ty:ident : $gd_method:ident;
)*
) => (
$(
impl_common_method!(
$(#[$attr])*
pub fn $name(&self $(,$pname : $pty)*) -> $Ty : $gd_method
);
)*
)
}
macro_rules! impl_guard_common_trait {
(
Drop for $Type:ident { $access:ident, $len:ident, } : $gd_method:ident
) => {
impl<'a> Drop for $Type<'a> {
fn drop(&mut self) {
unsafe {
($crate::private::get_api().$gd_method)(self.$access);
}
}
}
};
(
Clone for $Type:ident { $access:ident, $len:ident, } : $gd_method:ident
) => {
impl<'a> Clone for $Type<'a> {
fn clone(&self) -> Self {
let $access = unsafe { ($crate::private::get_api().$gd_method)(self.$access) };
$Type {
$access,
$len: self.$len,
_marker: std::marker::PhantomData,
}
}
}
};
}
macro_rules! define_access_guard {
(
pub struct $Type:ident<'a>: $AccessPtr:ty {
$access:ident = $access_gd_method:ident($BasePtr:ty),
$len:ident = $len_gd_method:ident,
}
Guard<Target=$Target:ident> => $guard_gd_method:ident -> $OrigPtr:ty;
$( $Trait:ident => $trait_gd_method:ident; )*
) => {
pub struct $Type<'a> {
$access: *mut $AccessPtr,
$len: usize,
_marker: std::marker::PhantomData<&'a $Target>,
}
impl<'a> $Type<'a> {
unsafe fn new(arr: $BasePtr) -> Self {
let $len = ($crate::private::get_api().$len_gd_method)(arr) as usize;
let $access = ($crate::private::get_api().$access_gd_method)(arr);
$Type {
$access,
$len,
_marker: std::marker::PhantomData,
}
}
}
unsafe impl<'a> $crate::access::Guard for $Type<'a> {
type Target = $Target;
fn len(&self) -> usize { self.$len }
fn read_ptr(&self) -> *const Self::Target {
unsafe {
let orig_ptr: $OrigPtr = ($crate::private::get_api().$guard_gd_method)(self.$access);
orig_ptr as *const Self::Target
}
}
}
$(
impl_guard_common_trait!(
$Trait for $Type { $access, $len, } : $trait_gd_method
);
)*
};
(
pub struct $Type:ident<'a>: $AccessPtr:ty {
$access:ident = $access_gd_method:ident($BasePtr:ty),
$len:ident = $len_gd_method:ident,
}
Guard<Target=$Target:ident> + WritePtr => $guard_gd_method:ident -> $OrigPtr:ty;
$( $Trait:ident => $trait_gd_method:ident; )*
) => {
define_access_guard!(
pub struct $Type<'a>: $AccessPtr {
$access = $access_gd_method($BasePtr),
$len = $len_gd_method,
}
Guard<Target=$Target> => $guard_gd_method -> $OrigPtr;
$( $Trait => $trait_gd_method; )*
);
unsafe impl<'a> $crate::access::WritePtr for $Type<'a> { }
};
}
macro_rules! godot_test {
($($test_name:ident $body:block)*) => {
$(
#[cfg(feature = "gd_test")]
#[doc(hidden)]
pub fn $test_name() -> bool {
let str_name = stringify!($test_name);
println!(" -- {}", str_name);
let ok = ::std::panic::catch_unwind(
|| $body
).is_ok();
if !ok {
godot_error!(" !! Test {} failed", str_name);
}
ok
}
)*
}
}
#[deprecated(
since = "0.8.1",
note = "Low-level registration is no longer supported. Use the NativeClass trait instead."
)]
#[macro_export]
macro_rules! godot_wrap_constructor {
($_name:ty, $c:expr) => {{
panic!("godot_wrap_constructor macro used")
}};
}
#[deprecated(
since = "0.8.1",
note = "Low-level registration is no longer supported. Use the NativeClass trait instead."
)]
#[macro_export]
macro_rules! godot_wrap_destructor {
($name:ty) => {{
panic!("godot_wrap_destructor macro used")
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! godot_wrap_method_parameter_count {
() => {
0
};
($name:ident, $($other:ident,)*) => {
1 + godot_wrap_method_parameter_count!($($other,)*)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! godot_wrap_method_inner {
(
$type_name:ty,
$map_method:ident,
fn $method_name:ident(
$self:ident,
$owner:ident : $owner_ty:ty
$(,$pname:ident : $pty:ty)*
$(, #[opt] $opt_pname:ident : $opt_pty:ty)*
) -> $retty:ty
) => {
{
#[allow(unused_unsafe, unused_variables, unused_assignments, unused_mut)]
#[allow(clippy::transmute_ptr_to_ptr)]
unsafe extern "C" fn method(
this: *mut $crate::sys::godot_object,
method_data: *mut $crate::libc::c_void,
user_data: *mut $crate::libc::c_void,
num_args: $crate::libc::c_int,
args: *mut *mut $crate::sys::godot_variant
) -> $crate::sys::godot_variant {
use std::panic::{self, AssertUnwindSafe};
use $crate::Instance;
if user_data.is_null() {
godot_error!(
"gdnative-core: user data pointer for {} is null (did the constructor fail?)",
stringify!($type_name),
);
return $crate::Variant::new().forget();
}
let __catch_result = panic::catch_unwind(move || {
let __instance: Instance<$type_name> = Instance::from_raw(this, user_data);
let num_args = num_args as isize;
let num_required_params = godot_wrap_method_parameter_count!($($pname,)*);
if num_args < num_required_params {
godot_error!("Incorrect number of parameters: required {} but got {}", num_required_params, num_args);
return $crate::Variant::new();
}
let num_optional_params = godot_wrap_method_parameter_count!($($opt_pname,)*);
let num_max_params = num_required_params + num_optional_params;
if num_args > num_max_params {
godot_error!("Incorrect number of parameters: expected at most {} but got {}", num_max_params, num_args);
return $crate::Variant::new();
}
let mut offset = 0;
$(
let _variant: &$crate::Variant = ::std::mem::transmute(&mut **(args.offset(offset)));
let $pname = match <$pty as $crate::FromVariant>::from_variant(_variant) {
Ok(val) => val,
Err(err) => {
godot_error!(
"Cannot convert argument #{idx} ({name}) to {ty}: {err} (non-primitive types may impose structural checks)",
idx = offset + 1,
name = stringify!($pname),
ty = stringify!($pty),
err = err,
);
return $crate::Variant::new();
},
};
offset += 1;
)*
$(
let $opt_pname = if offset < num_args {
let _variant: &$crate::Variant = ::std::mem::transmute(&mut **(args.offset(offset)));
let $opt_pname = match <$opt_pty as $crate::FromVariant>::from_variant(_variant) {
Ok(val) => val,
Err(err) => {
godot_error!(
"Cannot convert argument #{idx} ({name}) to {ty}: {err} (non-primitive types may impose structural checks)",
idx = offset + 1,
name = stringify!($opt_pname),
ty = stringify!($opt_pty),
err = err,
);
return $crate::Variant::new();
},
};
offset += 1;
$opt_pname
}
else {
<$opt_pty as ::std::default::Default>::default()
};
)*
let __ret = __instance
.$map_method(|__rust_val, $owner| {
let ret = __rust_val.$method_name($owner, $($pname,)* $($opt_pname,)*);
<$retty as $crate::ToVariant>::to_variant(&ret)
})
.unwrap_or_else(|err| {
godot_error!("gdnative-core: method call failed with error: {:?}", err);
godot_error!("gdnative-core: check module level documentation on gdnative::user_data for more information");
$crate::Variant::new()
});
std::mem::drop(__instance);
__ret
});
__catch_result
.unwrap_or_else(|_err| {
godot_error!("gdnative-core: method panicked (check stderr for output)");
$crate::Variant::new()
})
.forget()
}
method
}
};
}
#[macro_export]
macro_rules! godot_wrap_method {
(
$type_name:ty,
fn $method_name:ident(
&mut $self:ident,
$owner:ident : $owner_ty:ty
$(,$pname:ident : $pty:ty)*
$(,#[opt] $opt_pname:ident : $opt_pty:ty)*
$(,)?
) -> $retty:ty
) => {
godot_wrap_method_inner!(
$type_name,
map_mut_aliased,
fn $method_name(
$self,
$owner: $owner_ty
$(,$pname : $pty)*
$(,#[opt] $opt_pname : $opt_pty)*
) -> $retty
)
};
(
$type_name:ty,
fn $method_name:ident(
& $self:ident,
$owner:ident : $owner_ty:ty
$(,$pname:ident : $pty:ty)*
$(,#[opt] $opt_pname:ident : $opt_pty:ty)*
$(,)?
) -> $retty:ty
) => {
godot_wrap_method_inner!(
$type_name,
map_aliased,
fn $method_name(
$self,
$owner: $owner_ty
$(,$pname : $pty)*
$(,#[opt] $opt_pname : $opt_pty)*
) -> $retty
)
};
(
$type_name:ty,
fn $method_name:ident(
&mut $self:ident,
$owner:ident : $owner_ty:ty
$(,$pname:ident : $pty:ty)*
$(,#[opt] $opt_pname:ident : $opt_pty:ty)*
$(,)?
)
) => {
godot_wrap_method!(
$type_name,
fn $method_name(
&mut $self,
$owner: $owner_ty
$(,$pname : $pty)*
$(,#[opt] $opt_pname : $opt_pty)*
) -> ()
)
};
(
$type_name:ty,
fn $method_name:ident(
& $self:ident,
$owner:ident : $owner_ty:ty
$(,$pname:ident : $pty:ty)*
$(,#[opt] $opt_pname:ident : $opt_pty:ty)*
$(,)?
)
) => {
godot_wrap_method!(
$type_name,
fn $method_name(
& $self,
$owner: $owner_ty
$(,$pname : $pty)*
$(,#[opt] $opt_pname : $opt_pty)*
) -> ()
)
};
}