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;