Skip to main content

mono_rt/
types.rs

1//! Mono type wrappers and utilities.
2//!
3//! Provides safe, transparent wrappers around Mono pointer types.
4
5mod array;
6mod assembly;
7mod class;
8mod class_field;
9mod domain;
10mod image;
11mod method;
12mod mono_type;
13mod object;
14mod string;
15mod thread;
16mod type_kind;
17mod value;
18mod vtable;
19
20pub use array::MonoArray;
21pub use assembly::MonoAssembly;
22pub use class::MonoClass;
23pub use class_field::MonoClassField;
24pub use domain::MonoDomain;
25pub use image::MonoImage;
26pub use method::MonoMethod;
27pub use mono_type::MonoType;
28pub use object::MonoObject;
29pub use string::MonoString;
30pub use thread::MonoThread;
31pub use type_kind::TypeKind;
32pub use value::Value;
33pub use vtable::MonoVTable;
34
35use std::ffi::c_void;
36
37pub type MonoFunc = unsafe extern "C" fn(data: *mut c_void, user_data: *mut c_void);
38
39/// Generates a `!Send + !Sync` transparent wrapper around an opaque Mono pointer.
40///
41/// All handle types produced by this macro share the same threading contract, documented
42/// on the generated struct below.
43macro_rules! mono_handle {
44    ($name:ident) => {
45        use std::{ffi::c_void, ptr::NonNull};
46
47        /// An opaque handle to a Mono runtime object.
48        ///
49        /// # Thread safety
50        ///
51        /// This type is intentionally `!Send + !Sync`. Every thread that reads or writes
52        /// Mono objects must first be registered with the runtime via
53        /// [`crate::MonoThreadGuard::attach`]. Using a handle on an unregistered thread is
54        /// undefined behavior — Mono's garbage collector and internal bookkeeping assume all
55        /// active threads are known to the runtime.
56        ///
57        /// Handles are therefore bound to the thread on which they were obtained. The
58        /// compiler enforces this: a handle cannot be moved to another thread without
59        /// explicit `unsafe` code.
60        ///
61        /// If you need to transfer a handle across thread boundaries and you can guarantee
62        /// that *both* threads are attached to the runtime for the entire duration of use,
63        /// you can opt in manually on your wrapper type:
64        ///
65        /// ```rust,ignore
66        /// struct MyComponent {
67        ///     class: mono_rt::MonoClass,
68        /// }
69        ///
70        /// // SAFETY: `class` is only accessed while the calling thread holds a
71        /// // `MonoThreadGuard`, ensuring it is registered with the Mono runtime.
72        /// unsafe impl Send for MyComponent {}
73        /// unsafe impl Sync for MyComponent {}
74        /// ```
75        #[repr(transparent)]
76        #[derive(Clone, Copy, Debug)]
77        pub struct $name(NonNull<c_void>);
78
79        impl $name {
80            #[must_use]
81            pub fn as_ptr(self) -> *mut c_void {
82                self.0.as_ptr()
83            }
84
85            #[must_use]
86            pub fn from_ptr(ptr: *mut c_void) -> Option<Self> {
87                NonNull::new(ptr).map(Self)
88            }
89
90            /// # Safety
91            ///
92            /// `ptr` must be non-null and valid on a thread attached to the Mono runtime.
93            #[must_use]
94            pub unsafe fn from_ptr_unchecked(ptr: *mut c_void) -> Self {
95                Self(unsafe { NonNull::new_unchecked(ptr) })
96            }
97        }
98    };
99}
100pub(crate) use mono_handle;