Skip to main content

mono_rt/types/
method.rs

1use std::ffi::CStr;
2
3use super::{MonoObject, Value, mono_handle};
4use crate::{MonoError, Result, api};
5
6use std::ptr;
7
8mono_handle!(MonoMethod);
9
10impl MonoMethod {
11    /// Returns the name of this method as reported by the Mono runtime.
12    ///
13    /// The returned string is copied out of Mono's metadata and is safe to use beyond the
14    /// lifetime of the runtime handle.
15    ///
16    /// # Errors
17    ///
18    /// Returns [`MonoError::Uninitialized`] if the Mono API has not been initialized.
19    pub fn name(self) -> Result<String> {
20        let ptr = api()?.method_get_name(self.as_ptr());
21        if ptr.is_null() {
22            return Ok(String::new());
23        }
24        Ok(unsafe { CStr::from_ptr(ptr) }
25            .to_string_lossy()
26            .into_owned())
27    }
28
29    /// Invokes the method on `obj` (null for static methods) with the given arguments.
30    ///
31    /// Returns `Ok(Some(result))` on success, `Ok(None)` when the method returns void, and
32    /// `Err(MonoError::ManagedException(exc))` when the invocation throws a managed exception.
33    ///
34    /// # Errors
35    ///
36    /// Returns [`MonoError::ManagedException`] when a managed exception is thrown.
37    /// Returns [`MonoError::Uninitialized`] if the Mono API has not been initialized.
38    ///
39    /// # Safety
40    ///
41    /// `obj` and `args` must be valid Mono objects/arguments matching the method signature.
42    pub unsafe fn invoke(
43        self,
44        obj: *mut c_void,
45        args: *mut *mut c_void,
46    ) -> Result<Option<MonoObject>> {
47        let mut exc = ptr::null_mut::<c_void>();
48        let result = api()?.runtime_invoke(self.as_ptr(), obj, args, ptr::addr_of_mut!(exc));
49
50        if !exc.is_null() {
51            let exc_obj = unsafe { MonoObject::from_ptr_unchecked(exc) };
52            return Err(MonoError::ManagedException(exc_obj));
53        }
54
55        Ok(MonoObject::from_ptr(result))
56    }
57
58    /// Typed variant of [`invoke`](Self::invoke): builds the args array from `args` automatically.
59    ///
60    /// Prefer this over `invoke` when argument types are known at compile time. The caller is still
61    /// responsible for matching the `Value` variants to the method's actual parameter types.
62    ///
63    /// # Errors
64    ///
65    /// Returns [`MonoError::ManagedException`] when a managed exception is thrown.
66    /// Returns [`MonoError::Uninitialized`] if the Mono API has not been initialized.
67    ///
68    /// # Safety
69    ///
70    /// `obj` must be a valid Mono object pointer (or null for static methods). Each [`Value`]
71    /// in `args` must correspond to the correct parameter type expected by the method.
72    pub unsafe fn invoke_with(
73        self,
74        obj: *mut c_void,
75        args: &[Value],
76    ) -> Result<Option<MonoObject>> {
77        let mut ptrs: Vec<*mut c_void> = args.iter().map(Value::as_arg_ptr).collect();
78        let args_ptr = if ptrs.is_empty() {
79            std::ptr::null_mut()
80        } else {
81            ptrs.as_mut_ptr()
82        };
83        unsafe { self.invoke(obj, args_ptr) }
84    }
85}