gdnative_core/export/
method.rs

1//! Method registration
2
3use std::borrow::Cow;
4use std::marker::PhantomData;
5use std::{fmt, ops};
6
7use crate::core_types::{FromVariant, FromVariantError, Variant};
8use crate::export::class::NativeClass;
9use crate::export::{class_registry, ClassBuilder};
10use crate::log::Site;
11use crate::object::ownership::Shared;
12use crate::object::{Ref, TInstance, TRef};
13
14/// Builder type used to register a method on a `NativeClass`.
15#[must_use = "MethodBuilder left unbuilt -- did you forget to call done() or done_stateless()?"]
16pub struct MethodBuilder<'a, C, F> {
17    class_builder: &'a ClassBuilder<C>,
18    name: &'a str,
19    method: F,
20
21    rpc_mode: RpcMode,
22}
23
24impl<'a, C, F> MethodBuilder<'a, C, F>
25where
26    C: NativeClass,
27    F: Method<C>,
28{
29    pub(super) fn new(class_builder: &'a ClassBuilder<C>, name: &'a str, method: F) -> Self {
30        MethodBuilder {
31            class_builder,
32            name,
33            method,
34            rpc_mode: RpcMode::Disabled,
35        }
36    }
37
38    /// Set a RPC mode for this method.
39    #[inline]
40    pub fn with_rpc_mode(mut self, rpc_mode: RpcMode) -> Self {
41        self.rpc_mode = rpc_mode;
42        self
43    }
44
45    /// Register the method.
46    #[inline]
47    pub fn done(self) {
48        let method_data = Box::into_raw(Box::new(self.method));
49
50        let script_method = ScriptMethod {
51            name: self.name,
52            method_ptr: Some(method_wrapper::<C, F>),
53            attributes: ScriptMethodAttributes {
54                rpc_mode: self.rpc_mode,
55            },
56            method_data: method_data as *mut libc::c_void,
57            free_func: Some(free_func::<F>),
58        };
59
60        self.class_builder.add_method(script_method);
61    }
62}
63
64impl<'a, C, F> MethodBuilder<'a, C, F>
65where
66    C: NativeClass,
67    F: Method<C> + Copy + Default,
68{
69    /// Register the method as a stateless method. Stateless methods do not have data
70    /// pointers and destructors and are thus slightly lighter. This is intended for ZSTs,
71    /// but can be used with any `Method` type with `Copy + Default`.
72    #[inline]
73    pub fn done_stateless(self) {
74        let script_method = ScriptMethod {
75            name: self.name,
76            method_ptr: Some(method_wrapper::<C, Stateless<F>>),
77            attributes: ScriptMethodAttributes {
78                rpc_mode: self.rpc_mode,
79            },
80
81            // Stateless<F> is a ZST for any type F, so we can use any non-zero value as
82            // a valid pointer for it.
83            method_data: 1 as *mut libc::c_void,
84            free_func: None,
85        };
86
87        self.class_builder.add_method(script_method);
88    }
89}
90
91type ScriptMethodFn = unsafe extern "C" fn(
92    *mut sys::godot_object,
93    *mut libc::c_void,
94    *mut libc::c_void,
95    libc::c_int,
96    *mut *mut sys::godot_variant,
97) -> sys::godot_variant;
98
99#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
100pub enum RpcMode {
101    Disabled,
102    Remote,
103    RemoteSync,
104    Master,
105    Puppet,
106    MasterSync,
107    PuppetSync,
108}
109
110impl Default for RpcMode {
111    #[inline]
112    fn default() -> Self {
113        RpcMode::Disabled
114    }
115}
116
117impl RpcMode {
118    pub(crate) fn sys(self) -> sys::godot_method_rpc_mode {
119        match self {
120            RpcMode::Master => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_MASTER,
121            RpcMode::Remote => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_REMOTE,
122            RpcMode::Puppet => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_PUPPET,
123            RpcMode::RemoteSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_REMOTESYNC,
124            RpcMode::Disabled => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_DISABLED,
125            RpcMode::MasterSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_MASTERSYNC,
126            RpcMode::PuppetSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_PUPPETSYNC,
127        }
128    }
129}
130
131pub(crate) struct ScriptMethodAttributes {
132    pub rpc_mode: RpcMode,
133}
134
135pub(crate) struct ScriptMethod<'l> {
136    pub name: &'l str,
137    pub method_ptr: Option<ScriptMethodFn>,
138    pub attributes: ScriptMethodAttributes,
139
140    pub method_data: *mut libc::c_void,
141    pub free_func: Option<unsafe extern "C" fn(*mut libc::c_void) -> ()>,
142}
143
144/// Safe low-level trait for stateful, variadic methods that can be called on a native script type.
145pub trait Method<C: NativeClass>: Send + Sync + 'static {
146    /// Calls the method on `this` with `args`.
147    fn call(&self, this: TInstance<'_, C>, args: Varargs<'_>) -> Variant;
148
149    /// Returns an optional site where this method is defined. Used for logging errors in FFI wrappers.
150    ///
151    /// Default implementation returns `None`.
152    #[inline]
153    fn site() -> Option<Site<'static>> {
154        None
155    }
156}
157
158/// Wrapper for stateless methods that produces values with `Copy` and `Default`.
159struct Stateless<F> {
160    _marker: PhantomData<F>,
161}
162
163impl<C: NativeClass, F: Method<C> + Copy + Default> Method<C> for Stateless<F> {
164    fn call(&self, this: TInstance<'_, C>, args: Varargs<'_>) -> Variant {
165        let f = F::default();
166        f.call(this, args)
167    }
168}
169
170/// Adapter for methods whose arguments are statically determined. If the arguments would fail to
171/// type check, the method will print the errors to Godot's debug console and return `null`.
172#[derive(Clone, Copy, Default, Debug)]
173pub struct StaticArgs<F> {
174    f: F,
175}
176
177impl<F> StaticArgs<F> {
178    /// Wrap `f` in an adapter that implements `Method`.
179    #[inline]
180    pub fn new(f: F) -> Self {
181        StaticArgs { f }
182    }
183}
184
185/// Trait for methods whose argument lists are known at compile time. Not to be confused with a
186/// "static method".
187pub trait StaticArgsMethod<C: NativeClass>: Send + Sync + 'static {
188    type Args: FromVarargs;
189    fn call(&self, this: TInstance<'_, C>, args: Self::Args) -> Variant;
190
191    /// Returns an optional site where this method is defined. Used for logging errors in FFI wrappers.
192    ///
193    /// Default implementation returns `None`.
194    #[inline]
195    fn site() -> Option<Site<'static>> {
196        None
197    }
198}
199
200impl<C: NativeClass, F: StaticArgsMethod<C>> Method<C> for StaticArgs<F> {
201    #[inline]
202    fn call(&self, this: TInstance<'_, C>, mut args: Varargs<'_>) -> Variant {
203        match args.read_many::<F::Args>() {
204            Ok(parsed) => {
205                if let Err(err) = args.done() {
206                    err.with_site(F::site().unwrap_or_default()).log_error();
207                    return Variant::nil();
208                }
209                F::call(&self.f, this, parsed)
210            }
211            Err(errors) => {
212                for err in errors {
213                    err.with_site(F::site().unwrap_or_default()).log_error();
214                }
215                Variant::nil()
216            }
217        }
218    }
219
220    #[inline]
221    fn site() -> Option<Site<'static>> {
222        F::site()
223    }
224}
225
226/// Safe interface to a list of borrowed method arguments with a convenient API
227/// for common operations with them.
228///
229/// **Note:** the `impl Iterator` is deprecated, `Varargs` itself should not be treated as a consumable iterator.
230/// Instead, use [`Self::as_slice()`].
231///
232/// This type can be destructured into tuples:
233/// ```no_run
234/// use gdnative::prelude::*;
235/// use gdnative::export::Varargs;
236///
237/// #[derive(NativeClass)]
238/// #[no_constructor]
239/// struct MyClass {}
240///
241/// struct CalcMethod;
242/// impl Method<MyClass> for CalcMethod {
243///     fn call(
244///         &self,
245///         _this: TInstance<'_, MyClass>,
246///         args: Varargs<'_>,
247///     ) -> Variant {
248///         // Destructure via try_into():
249///         let (a, b): (i64, i64) = args.try_into().expect("signature mismatch");
250///         let ret = a * b;
251///         ret.to_variant()
252///     }
253/// }
254/// ```
255pub struct Varargs<'a> {
256    idx: usize,
257    args: &'a [&'a Variant],
258    offset_index: usize,
259}
260
261impl<'a> Varargs<'a> {
262    /// Returns the amount of arguments left.
263    #[inline]
264    pub fn len(&self) -> usize {
265        self.args.len() - self.idx
266    }
267
268    #[inline]
269    pub fn is_empty(&self) -> bool {
270        self.len() == 0
271    }
272
273    /// Returns a builder for reading the next argument, that can be used to refine
274    /// the error message on failure.
275    #[inline]
276    pub fn read<T: FromVariant>(&mut self) -> ArgBuilder<'_, 'a, T> {
277        ArgBuilder {
278            args: self,
279            name: None,
280            ty: None,
281            site: None,
282            _marker: PhantomData,
283        }
284    }
285
286    /// Parses a structure that implements `FromVarargs` incrementally from the
287    /// remaining arguments.
288    #[inline]
289    pub fn read_many<T: FromVarargs>(&mut self) -> Result<T, Vec<ArgumentError<'a>>> {
290        T::read(self)
291    }
292
293    /// Returns the remaining arguments as a slice of `Variant`s.
294    #[inline]
295    pub fn as_slice(&self) -> &'a [&'a Variant] {
296        &self.args[self.idx..]
297    }
298
299    /// Discard the rest of the arguments, and return an error if there is any.
300    ///
301    /// # Errors
302    ///
303    /// If there are any excess arguments left.
304    #[inline]
305    pub fn done(self) -> Result<(), ArgumentError<'a>> {
306        if self.is_empty() {
307            Ok(())
308        } else {
309            Err(ArgumentError {
310                site: None,
311                kind: ArgumentErrorKind::ExcessArguments {
312                    rest: self.as_slice(),
313                },
314            })
315        }
316    }
317
318    /// Create a typed interface from raw pointers. This is an internal interface.
319    ///
320    /// # Safety
321    ///
322    /// `args` must point to an array of valid `godot_variant` pointers of at least `num_args` long.
323    #[doc(hidden)]
324    #[inline]
325    pub unsafe fn from_sys(num_args: libc::c_int, args: *mut *mut sys::godot_variant) -> Self {
326        let args = std::slice::from_raw_parts(args, num_args as usize);
327        let args = std::mem::transmute::<&[*mut sys::godot_variant], &[&Variant]>(args);
328        Self {
329            idx: 0,
330            args,
331            offset_index: 0,
332        }
333    }
334
335    /// Check the length of arguments.
336    ///
337    /// See [`Self::get()`] or [`Self::get_opt()`] for examples.
338    ///
339    /// # Errors
340    /// Returns an [`VarargsError::InvalidLength`] if the length of arguments is outside the specified range.
341    #[inline]
342    pub fn check_length(&self, expected: impl Into<IndexBounds>) -> Result<(), VarargsError> {
343        let passed = self.args.len();
344        let expected = expected.into();
345        if expected.contains(passed) {
346            Ok(())
347        } else {
348            // Note: cannot use Box<dyn RangeBounds<usize>> because trait is not object-safe due to _unrelated_ method contains()
349            Err(VarargsError::InvalidLength {
350                length: passed,
351                expected,
352            })
353        }
354    }
355
356    /// Returns the type-converted value at the specified argument position.
357    ///
358    /// # Errors
359    /// Returns a [`VarargsError::InvalidArgumentType`] if the conversion fails or the argument is not set.
360    ///
361    /// # Examples
362    /// ```
363    /// # fn call(args: gdnative::export::Varargs) -> Result<(), Box<dyn std::error::Error>> {
364    ///     args.check_length(2)?;
365    ///     let a: usize = args.get(0)?;
366    ///     let rest: i64 = args.get(1)?;
367    /// # Ok(())
368    /// # }
369    /// ```
370    #[inline]
371    pub fn get<T: FromVariant>(&self, index: usize) -> Result<T, VarargsError> {
372        // Note: disregards iterator offset, since that representation is deprecated
373
374        match self.args.get(index) {
375            Some(v) => match T::from_variant(v) {
376                Ok(ok) => Ok(ok),
377                Err(error) => Err(VarargsError::InvalidArgumentType { index, error }),
378            },
379            None => {
380                let error = FromVariantError::Custom("Argument is not set".to_owned());
381                Err(VarargsError::InvalidArgumentType { index, error })
382            }
383        }
384    }
385
386    /// Returns the type-converted value at the specified argument position.
387    /// Returns `None` if the argument is not set.
388    ///
389    /// # Errors
390    /// Returns a [`VarargsError::InvalidArgumentType`] if the conversion fails.
391    ///
392    /// # Examples
393    /// ```
394    /// # fn call(args: gdnative::export::Varargs) -> Result<(), Box<dyn std::error::Error>> {
395    ///     args.check_length(1..=2)?;
396    ///     let a: usize = args.get(0)?;
397    ///     let rest: i64 = args.get_opt(1)?.unwrap_or(72);
398    /// # Ok(())
399    /// # }
400    /// ```
401    #[inline]
402    pub fn get_opt<T: FromVariant>(&self, index: usize) -> Result<Option<T>, VarargsError> {
403        // Note: disregards iterator offset, since that representation is deprecated
404
405        match self.args.get(index) {
406            Some(v) => match T::from_variant(v) {
407                Ok(ok) => Ok(Some(ok)),
408                Err(error) => Err(VarargsError::InvalidArgumentType { index, error }),
409            },
410            None => Ok(None),
411        }
412    }
413}
414
415impl<'a> Iterator for Varargs<'a> {
416    type Item = &'a Variant;
417    #[inline]
418    fn next(&mut self) -> Option<Self::Item> {
419        let ret = self.args.get(self.idx);
420        ret.map(|&v| {
421            self.idx += 1;
422            v
423        })
424    }
425}
426
427// Return a second token.
428macro_rules! replace_expr {
429    ($_t:tt $sub:expr) => {
430        $sub
431    };
432}
433
434// Count parameters.
435macro_rules! count_tts {
436    ($($tts:tt)*) => {
437        0usize $(+ replace_expr!($tts 1usize))*
438    };
439}
440
441// Convert from Varargs to tuples, implement traits.
442macro_rules! varargs_into_tuple {
443    ($($params:ident),*) => {
444        impl<'a, $($params: FromVariant),*> std::convert::TryFrom<Varargs<'a>> for ($($params,)*) {
445            type Error = VarargsError;
446
447            #[inline]
448            fn try_from(args: Varargs<'a>) -> Result<Self, Self::Error> {
449                const EXPECTED: usize = count_tts!($($params)*);
450                args.check_length(EXPECTED)?;
451                let mut i: usize = 0;
452                #[allow(unused_variables, unused_mut)]
453                let mut inc = || {
454                    let ret = i;
455                    i += 1;
456                    ret
457                };
458                Ok((
459                    $(args.get::<$params>(inc())?,)*
460                ))
461            }
462        }
463    };
464}
465
466// Define up to the length supported by standard library.
467varargs_into_tuple!();
468varargs_into_tuple!(A);
469varargs_into_tuple!(A, B);
470varargs_into_tuple!(A, B, C);
471varargs_into_tuple!(A, B, C, D);
472varargs_into_tuple!(A, B, C, D, E);
473varargs_into_tuple!(A, B, C, D, E, F);
474varargs_into_tuple!(A, B, C, D, E, F, G);
475varargs_into_tuple!(A, B, C, D, E, F, G, H);
476varargs_into_tuple!(A, B, C, D, E, F, G, H, I);
477varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J);
478varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J, K);
479varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
480
481/// All possible errors that can occur when converting from Varargs.
482///
483/// For methods that return this error, see [`Varargs::check_length()`], [`Varargs::get()`] or [`Varargs::get_opt()`].
484/// Another context where this type is used is when destructuring `Varargs` into tuples.
485#[derive(Debug)]
486pub enum VarargsError {
487    /// At least one argument type mismatches.
488    InvalidArgumentType {
489        index: usize,
490        error: FromVariantError,
491    },
492    /// Number of arguments doesn't match expectations.
493    InvalidLength {
494        /// The number of arguments actually passed.
495        length: usize,
496        expected: IndexBounds,
497    },
498}
499
500impl std::error::Error for VarargsError {}
501
502impl fmt::Display for VarargsError {
503    #[inline]
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        match self {
506            VarargsError::InvalidArgumentType { index, error } => {
507                write!(f, "type error for argument #{index}: {error}")?
508            }
509            VarargsError::InvalidLength { expected, length } => write!(
510                f,
511                "length mismatch: expected range {expected}, actual {length}"
512            )?,
513        }
514
515        Ok(())
516    }
517}
518
519/// Defines which number of arguments is valid.
520///
521/// Convertible from an exact value `a` as well as inclusive range expressions `a..`, `..=b`, `a..=b`.
522pub struct IndexBounds {
523    /// The lower (inclusive) bound of the expected number of arguments, or `None` if unbounded.
524    pub start: Option<usize>,
525
526    /// The upper (inclusive) bound of the expected number of arguments, or `None` if unbounded.
527    pub end: Option<usize>,
528}
529
530impl IndexBounds {
531    #[inline]
532    pub fn contains(&self, value: usize) -> bool {
533        match (self.start, self.end) {
534            (Some(s), Some(e)) => value >= s && value <= e,
535            (Some(s), None) => value >= s,
536            (None, Some(e)) => value <= e,
537            (None, None) => false, // unreachable in this context, but can be constructed by user
538        }
539    }
540}
541
542/// `a`
543impl From<usize> for IndexBounds {
544    #[inline]
545    fn from(exact_value: usize) -> Self {
546        Self {
547            start: Some(exact_value),
548            end: Some(exact_value),
549        }
550    }
551}
552
553/// `a..=b`
554impl From<ops::RangeInclusive<usize>> for IndexBounds {
555    #[inline]
556    fn from(range: ops::RangeInclusive<usize>) -> Self {
557        Self {
558            start: Some(*range.start()),
559            end: Some(*range.end()),
560        }
561    }
562}
563
564/// `a..`
565impl From<ops::RangeFrom<usize>> for IndexBounds {
566    #[inline]
567    fn from(range: ops::RangeFrom<usize>) -> Self {
568        Self {
569            start: Some(range.start),
570            end: None,
571        }
572    }
573}
574
575/// `..=b`
576impl From<ops::RangeToInclusive<usize>> for IndexBounds {
577    #[inline]
578    fn from(range: ops::RangeToInclusive<usize>) -> Self {
579        Self {
580            start: None,
581            end: Some(range.end),
582        }
583    }
584}
585
586impl fmt::Debug for IndexBounds {
587    #[inline]
588    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589        write!(f, "IndexBounds({self})")
590    }
591}
592
593impl fmt::Display for IndexBounds {
594    #[inline]
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        if let Some(start) = self.start {
597            write!(f, "{start}")?
598        }
599
600        write!(f, "..=")?;
601
602        if let Some(end) = self.end {
603            write!(f, "{end}")?
604        }
605
606        Ok(())
607    }
608}
609
610/// Trait for structures that can be parsed from `Varargs`.
611///
612/// This trait can be derived for structure types where each type implements `FromVariant`.
613/// The order of fields matter for this purpose:
614///
615/// ```ignore
616/// #[derive(FromVarargs)]
617/// struct MyArgs {
618///     foo: i32,
619///     bar: String,
620///     #[opt] baz: Option<Ref<Node>>,
621/// }
622/// ```
623pub trait FromVarargs: Sized {
624    fn read<'a>(args: &mut Varargs<'a>) -> Result<Self, Vec<ArgumentError<'a>>>;
625}
626
627/// Builder for providing additional argument information for error reporting.
628pub struct ArgBuilder<'r, 'a, T> {
629    args: &'r mut Varargs<'a>,
630    name: Option<Cow<'a, str>>,
631    ty: Option<Cow<'a, str>>,
632    site: Option<Site<'a>>,
633    _marker: PhantomData<T>,
634}
635
636impl<'r, 'a, T> ArgBuilder<'r, 'a, T> {
637    /// Provides a name for this argument. If an old name is already set, it is
638    /// silently replaced. The name can either be borrowed from the environment
639    /// or owned.
640    #[inline]
641    pub fn with_name<S: Into<Cow<'a, str>>>(mut self, name: S) -> Self {
642        self.name = Some(name.into());
643        self
644    }
645
646    /// Provides a more readable type name for this argument. If an old name is
647    /// already set, it is silently replaced. If no type name is given, a value
648    /// from `std::any::type_name` is used. The name can either be borrowed from
649    /// the environment or owned.
650    #[inline]
651    pub fn with_type_name<S: Into<Cow<'a, str>>>(mut self, ty: S) -> Self {
652        self.ty = Some(ty.into());
653        self
654    }
655
656    /// Provides a call site for this argument. If an old call site is already set,
657    /// it is silently replaced. If given, the site will be used in case of error.
658    #[inline]
659    pub fn with_site(mut self, site: Site<'a>) -> Self {
660        self.site = Some(site);
661        self
662    }
663}
664
665impl<'r, 'a, T: FromVariant> ArgBuilder<'r, 'a, T> {
666    /// Get the converted argument value.
667    ///
668    /// # Errors
669    ///
670    /// If the argument is missing, or cannot be converted to the desired type.
671    #[inline]
672    pub fn get(mut self) -> Result<T, ArgumentError<'a>> {
673        self.get_optional_internal().and_then(|arg| {
674            let actual_index = self.args.idx + self.args.offset_index;
675            arg.ok_or(ArgumentError {
676                site: self.site,
677                kind: ArgumentErrorKind::Missing {
678                    idx: actual_index,
679                    name: self.name,
680                },
681            })
682        })
683    }
684
685    /// Get the argument as optional.
686    ///
687    /// # Errors
688    ///
689    /// If the argument is present, but cannot be converted to the desired type.
690    #[inline]
691    pub fn get_optional(mut self) -> Result<Option<T>, ArgumentError<'a>> {
692        self.get_optional_internal()
693    }
694
695    fn get_optional_internal(&mut self) -> Result<Option<T>, ArgumentError<'a>> {
696        let Self {
697            site,
698            args,
699            name,
700            ty,
701            ..
702        } = self;
703        let actual_index = args.idx + args.offset_index;
704
705        if let Some(arg) = args.next() {
706            T::from_variant(arg).map(Some).map_err(|err| ArgumentError {
707                site: *site,
708                kind: ArgumentErrorKind::CannotConvert {
709                    idx: actual_index,
710                    name: name.take(),
711                    value: arg,
712                    ty: ty
713                        .take()
714                        .unwrap_or_else(|| Cow::Borrowed(std::any::type_name::<T>())),
715                    err,
716                },
717            })
718        } else {
719            Ok(None)
720        }
721    }
722}
723
724/// Error during argument parsing.
725#[derive(Debug)]
726pub struct ArgumentError<'a> {
727    site: Option<Site<'a>>,
728    kind: ArgumentErrorKind<'a>,
729}
730
731impl<'a> std::error::Error for ArgumentError<'a> {}
732impl<'a> fmt::Display for ArgumentError<'a> {
733    #[inline]
734    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
735        if let Some(site) = &self.site {
736            write!(f, "at {site}: ")?;
737        }
738        write!(f, "{}", self.kind)
739    }
740}
741
742impl<'a> ArgumentError<'a> {
743    /// Assign a call site for this error. If an old one is already set, it is silently
744    /// replaced.
745    #[inline]
746    pub fn with_site(mut self, site: Site<'a>) -> Self {
747        self.site = Some(site);
748        self
749    }
750
751    /// Print this error in the Godot debug console as a warning.
752    ///
753    /// # Panics
754    ///
755    /// If the API isn't initialized.
756    #[inline]
757    pub fn log_warn(&self) {
758        crate::log::warn(self.site.unwrap_or_default(), &self.kind);
759    }
760
761    /// Print this error in the Godot debug console as an error.
762    ///
763    /// # Panics
764    ///
765    /// If the API isn't initialized.
766    #[inline]
767    pub fn log_error(&self) {
768        crate::log::error(self.site.unwrap_or_default(), &self.kind);
769    }
770}
771
772/// Error during argument parsing.
773#[derive(Debug)]
774enum ArgumentErrorKind<'a> {
775    Missing {
776        idx: usize,
777        name: Option<Cow<'a, str>>,
778    },
779    CannotConvert {
780        idx: usize,
781        name: Option<Cow<'a, str>>,
782        ty: Cow<'a, str>,
783        value: &'a Variant,
784        err: FromVariantError,
785    },
786    ExcessArguments {
787        rest: &'a [&'a Variant],
788    },
789}
790
791impl<'a> std::error::Error for ArgumentErrorKind<'a> {}
792
793impl<'a> fmt::Display for ArgumentErrorKind<'a> {
794    #[inline]
795    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796        use ArgumentErrorKind as E;
797
798        match self {
799            E::Missing {
800                idx,
801                name: Some(name),
802            } => {
803                write!(f, "missing non-optional parameter `{name}` (#{idx})")
804            }
805            E::Missing { idx, name: None } => {
806                write!(f, "missing non-optional parameter #{idx}")
807            }
808            E::CannotConvert {
809                idx,
810                name: Some(name),
811                value,
812                ty,
813                err,
814            } => {
815                write!(f,
816                    "cannot convert argument `{name}` (#{idx}, {value:?}) to {ty}: {err} (non-primitive types may impose structural checks)"
817                )
818            }
819            E::CannotConvert {
820                idx,
821                name: None,
822                value,
823                ty,
824                err,
825            } => {
826                write!(f,
827                    "cannot convert argument #{idx} ({value:?}) to {ty}: {err} (non-primitive types may impose structural checks)"
828                )
829            }
830            E::ExcessArguments { rest } => {
831                if rest.len() > 1 {
832                    write!(
833                        f,
834                        "{} excessive arguments are given: {:?}",
835                        rest.len(),
836                        rest
837                    )
838                } else {
839                    write!(f, "an excessive argument is given: {:?}", rest[0])
840                }
841            }
842        }
843    }
844}
845
846unsafe extern "C" fn method_wrapper<C: NativeClass, F: Method<C>>(
847    this: *mut sys::godot_object,
848    method_data: *mut libc::c_void,
849    user_data: *mut libc::c_void,
850    num_args: libc::c_int,
851    args: *mut *mut sys::godot_variant,
852) -> sys::godot_variant {
853    if user_data.is_null() {
854        crate::log::error(
855            F::site().unwrap_or_default(),
856            format_args!(
857                "gdnative-core: user data pointer for {} is null (did the constructor fail?)",
858                class_registry::class_name_or_default::<C>(),
859            ),
860        );
861        return Variant::nil().leak();
862    }
863
864    let this = match std::ptr::NonNull::new(this) {
865        Some(this) => this,
866        None => {
867            crate::log::error(
868                F::site().unwrap_or_default(),
869                format_args!(
870                    "gdnative-core: base object pointer for {} is null (probably a bug in Godot)",
871                    class_registry::class_name_or_default::<C>(),
872                ),
873            );
874            return Variant::nil().leak();
875        }
876    };
877
878    let result = std::panic::catch_unwind(move || {
879        let method = &*(method_data as *const F);
880
881        let this: Ref<C::Base, Shared> = Ref::from_sys(this);
882        let this: TRef<'_, C::Base, _> = this.assume_safe_unchecked();
883        let this: TInstance<'_, C, _> = TInstance::from_raw_unchecked(this, user_data);
884
885        let args = Varargs::from_sys(num_args, args);
886
887        F::call(method, this, args)
888    });
889
890    result
891        .unwrap_or_else(|e| {
892            crate::log::error(
893                F::site().unwrap_or_default(),
894                "gdnative-core: method panicked (check stderr for output)",
895            );
896            crate::private::print_panic_error(e);
897            Variant::nil()
898        })
899        .leak()
900}
901
902unsafe extern "C" fn free_func<F>(method_data: *mut libc::c_void) {
903    drop(Box::from_raw(method_data as *mut F))
904}