1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::assembly::Assembly;
use crate::binds::{mono_domain_assembly_open, mono_domain_create, MonoDomain};
use crate::jit::esnure_thread_registered;
#[cfg(test)]
use crate::TEST_DOMAIN;
/// Safe representation of [`MonoDomain`] type.
#[derive(Eq, Clone, Copy)]
pub struct Domain {
ptr: *mut MonoDomain,
}
use std::ffi::CString;
use std::sync::LazyLock;
impl Domain {
/// Loads [`Assembly`] at path into domain, returns **None** if assembly could not be loaded(is missing or broken), and `Some(Assembly)` if it was successfully loaded.
#[must_use]
pub fn assembly_open(&self, path: &str) -> Option<Assembly> {
//! # Example
//!```no_run
//! # use wrapped_mono::*;
//! # let domain = jit::init("name",None);
//! let asm = domain.assembly_open("SomeAssembly.dll").expect("Could not load assembly!");
//!```
esnure_thread_registered();
self.attach_thread();
let cstr = CString::new(path).expect(crate::STR2CSTR_ERR);
let ptr = unsafe { mono_domain_assembly_open(self.get_ptr(), cstr.as_ptr()) };
if ptr.is_null() {
return None;
}
let _ = &cstr;
Some(unsafe { Assembly::from_ptr(ptr) })
}
/// Creates a new empty domain
/// # Example
/// ```no_run
/// # use wrapped_mono::*;
/// let domain1 = jit::init("name",None);
/// let domain2 = Domain::create();
/// ```
#[must_use]
pub fn create() -> Self {
unsafe { Self::from_ptr(mono_domain_create()) }
}
/// Sets domain confing to one loaded from file *filename* in directory *`base_directory`*.
pub fn set_config(&self, base_directory: &str, filename: &str) {
let bd_cstr = CString::new(base_directory).expect(crate::STR2CSTR_ERR);
let fnme_cstr = CString::new(filename).expect(crate::STR2CSTR_ERR);
unsafe {
crate::binds::mono_domain_set_config(self.ptr, bd_cstr.as_ptr(), fnme_cstr.as_ptr());
}
drop(bd_cstr);
drop(fnme_cstr);
}
/// Function creating [`Domain`] type from a pointer to [`MonoDomain`].
/// # Safety
/// Pointer must be a valid pointer to [`MonoDomain`].
pub unsafe fn from_ptr(ptr: *mut MonoDomain) -> Self {
Self { ptr }
}
/// Function returning internal pointer to [`MonoDomain`]
#[must_use]
pub fn get_ptr(&self) -> *mut MonoDomain {
self.ptr
}
/// Sets domain as the current domain.
pub fn set_current(&self, active: bool) {
unsafe { crate::binds::mono_domain_set(self.ptr, i32::from(active)) };
}
/// Attaches current thread (makes domain "aware" of this threads existence, allowing domain to eg. automatically stop it during garbage collection to prevent errors.) Should be done for all threads that will interact with this domain.
pub fn attach_thread(&self) {
unsafe { crate::binds::mono_jit_thread_attach(self.ptr) };
}
/* TODO: fix domain unloading/freeing
/// [DOES not work]
fn unload(self){
self.set(true);
self.attach();
unsafe{crate::binds::mono_domain_unload(self.ptr)};
drop(self);
}
/// Releases resources related to a specific domain. If *force* is true, allows releasing of the root domain. Used during shut-down.
/// # Safety
/// Since this function releases all resources related to given domain, it means that all references to objects inside it will become invalid.
fn free(self,force:bool){
unsafe{crate::binds::mono_domain_free(self.ptr,force as i32)};
drop(self);
}
*/
/// Returns current domain or `None` if mono runtime is not initialized yet.
#[must_use]
pub fn get_current() -> Option<Self> {
let ptr = unsafe { crate::binds::mono_domain_get() };
if ptr.is_null() {
None
} else {
unsafe { Some(Self::from_ptr(ptr)) }
}
}
}
// Allows you to compare two domains to check if they are one and the same.
impl std::cmp::PartialEq for Domain {
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
unsafe impl Send for Domain {}
#[test]
fn eq() {
let a = TEST_DOMAIN.lock().unwrap();
let a = *a;
let b = Domain::create();
assert!(a == a);
assert!(b != a);
assert!(a != b);
assert!(b == b);
}
#[test]
fn get_set_current() {
let domain = TEST_DOMAIN.lock().unwrap();
domain.attach_thread();
let domain = *domain;
domain.set_current(true);
assert!(domain == Domain::get_current().unwrap());
}