wrapped_mono/object.rs
1use crate::binds::MonoObject;
2use crate::gc::{gc_unsafe_enter, gc_unsafe_exit, GCHandle};
3use crate::interop::{InteropRecive, InteropSend};
4use crate::tupleutilis::{CompareClasses, TupleToFFIPtrs};
5#[allow(unused_imports)] // for docs
6// use crate::delegate::Delegate;
7use crate::{class::Class, domain::Domain, method::Method};
8///Safe representation of a refernece to a manged Object. Is **not nullable** when passed between managed and unmanged code(e.g when added as an argument to function exposed as an interna call).
9///It means that while it may represent a nullable type, wrapped-mono will automaticly panic when recived null value.
10///For nullable support use `Option<Object>`.
11pub struct Object {
12 #[cfg(not(feature = "referneced_objects"))]
13 obj_ptr: *mut MonoObject,
14 #[cfg(feature = "referneced_objects")]
15 handle: GCHandle,
16}
17use crate::mstring::MString;
18///Trait contining functions common for all types of manged objects.
19pub trait ObjectTrait: Sized + InteropClass {
20 fn cast<Target: ObjectTrait>(&self) -> Option<Target> {
21 #[cfg(feature = "referneced_objects")]
22 let marker = gc_unsafe_enter();
23 let res = unsafe { Target::from_ptr(self.get_ptr()) };
24 #[cfg(feature = "referneced_objects")]
25 gc_unsafe_exit(marker);
26 res
27 }
28 /// Gets the internal [`MonoObject`] pointer.
29 #[must_use]
30 fn get_ptr(&self) -> *mut MonoObject;
31 /// Creates new instance of [`Self`] from *mut [`MonoObject`]. Returns `None` if either `obj_ptr` is null OR object `obj_ptr` points to is of a type which does not derive from the managed type [`Self`] represents.
32 /// # Safety
33 /// Pointer must either be null, or point to a managed object.
34 #[must_use]
35 unsafe fn from_ptr(obj_ptr: *mut MonoObject) -> Option<Self> {
36 let class = Self::get_mono_class();
37 let obj_ptr = crate::binds::mono_object_isinst(obj_ptr, class.get_ptr());
38 if obj_ptr.is_null() {
39 None
40 } else {
41 Some(Self::from_ptr_unchecked(obj_ptr))
42 }
43 }
44 /// Creates new instance of [`Self`] from *mut [`MonoObject`]. Pointer is guaranteed to be not null, and of type which can be assigned to managed type represented by [`Self`].
45 /// # Safety
46 /// The pointer must not be null, and point to a managed Object of either type represented by [`Self`] or a type derived from it.
47 #[must_use]
48 unsafe fn from_ptr_unchecked(obj: *mut MonoObject) -> Self;
49 /// get hash of this object: This hash is **not** based on values of objects fields, and differs from result of calling object.GetHash()
50 /// # Example
51 /// ```no_run
52 /// # use wrapped_mono::*;
53 /// # let class = Class::get_int_32();
54 /// # let domain = Domain::get_current().unwrap();
55 /// let object = Object::new(&domain,&class);
56 /// let object_copy = object.clone_managed_object();
57 /// assert!(object.hash() != object_copy.hash()); // Objects object and object_copy have exacly
58 /// // the same values of their fileds, but are diffrent instances, so their hash is diffrent.
59 /// ```
60 #[must_use]
61 fn hash(&self) -> i32 {
62 #[cfg(feature = "referneced_objects")]
63 let marker = gc_unsafe_enter();
64 let hsh = unsafe { crate::binds::mono_object_hash(self.get_ptr()) };
65 #[cfg(feature = "referneced_objects")]
66 gc_unsafe_exit(marker);
67 hsh
68 }
69 /// get [`Domain`] this object exists in.
70 /// # Example
71 ///```no_run
72 /// # use wrapped_mono::*;
73 /// # let class = Class::get_int_32();
74 /// let domain = Domain::create(); //create Domain dom
75 /// let object = Object::new(&domain,&class); //create object in Domain dom.
76 /// let obj_domain = object.get_domain(); //get doamin object is in
77 /// assert!(domain == obj_domain);
78 ///```
79 #[must_use]
80 fn get_domain(&self) -> Domain {
81 #[cfg(feature = "referneced_objects")]
82 let marker = gc_unsafe_enter();
83 let dom = unsafe { Domain::from_ptr(crate::binds::mono_object_get_domain(self.get_ptr())) };
84 #[cfg(feature = "referneced_objects")]
85 gc_unsafe_exit(marker);
86 dom
87 }
88 /// get size of managed object referenced by *self* in bytes. Does include builtin hidden data.
89 /// # Example
90 ///```ignore
91 /// class SomeClass{};
92 /// class OtherClass{int some_int;};
93 ///```
94 ///```no_run
95 /// # use wrapped_mono::*;
96 /// # use wrapped_mono::binds::MonoObject;
97 /// # let domain = Domain::get_current().unwrap();
98 /// # let some_obj = Object::new(&domain,&Class::get_void());
99 /// # let other_obj = Object::box_val::<i32>(&domain,77);
100 /// let size = some_obj.get_size(); //Get size of some_obj(in this case an instance of SomeClass)
101 /// assert!(size == std::mem::size_of::<MonoObject>() as u32); // 8 bytes on 32 bit systems, 16 on 64 bit ones (size of two pointers).
102 /// let size_other = other_obj.get_size(); //Get size of other_obj(in this case an instance of OtherClass)
103 /// assert!(size_other == (std::mem::size_of::<MonoObject>() + std::mem::size_of::<i32>()) as u32); //size of two hidden pointers + some_int filed.
104 ///```
105 #[must_use]
106 fn get_size(&self) -> u32 {
107 #[cfg(feature = "referneced_objects")]
108 let marker = gc_unsafe_enter();
109 let size = unsafe { crate::binds::mono_object_get_size(self.get_ptr()) };
110 #[cfg(feature = "referneced_objects")]
111 gc_unsafe_exit(marker);
112 size
113 }
114 /// get reflection token
115 //TODO:extend this description to make it more clear
116 #[doc(hidden)]
117 fn reflection_get_token(&self) -> u32 {
118 #[cfg(feature = "referneced_objects")]
119 let marker = gc_unsafe_enter();
120 let tok = unsafe { crate::binds::mono_reflection_get_token(self.get_ptr()) };
121 #[cfg(feature = "referneced_objects")]
122 gc_unsafe_exit(marker);
123 tok
124 }
125 /// Returns [`Class`] of this object. NOTE: This is function returns the class of the underlying object, not class represented by [`Self`]. This means that class returned from `get_class` may be a class derived from class [`Self`] represents.
126 /// # Example
127 /// ```no_run
128 /// # use wrapped_mono::*;
129 /// # let domain = Domain::get_current().unwrap();
130 /// # let class = Class::get_void();
131 /// let object = Object::new(&domain,&class);
132 /// let object_class = object.get_class();
133 /// assert!(class == object_class);
134 /// ```
135 #[must_use]
136 fn get_class(&self) -> Class {
137 #[cfg(feature = "referneced_objects")]
138 let marker = gc_unsafe_enter();
139 let class = unsafe {
140 Class::from_ptr(crate::binds::mono_object_get_class(self.get_ptr()))
141 .expect("Could not get class of an object")
142 };
143 #[cfg(feature = "referneced_objects")]
144 gc_unsafe_exit(marker);
145 class
146 }
147 /// Returns result of calling `ToString` on this [`Object`].
148 /// # Errors
149 /// Returns [`Exception`] if raised, and [`Option<MString>`] if not. Function returns [`Option<MString>`] to allow for null value to be returned.
150 fn to_mstring(&self) -> Result<Option<MString>, Exception> {
151 #[cfg(feature = "referneced_objects")]
152 let marker = gc_unsafe_enter();
153 let mut exc: *mut crate::binds::MonoException = core::ptr::null_mut();
154 let res = unsafe {
155 MString::from_ptr(
156 crate::binds::mono_object_to_string(
157 self.get_ptr(),
158 std::ptr::addr_of_mut!(exc).cast::<*mut MonoObject>(),
159 )
160 .cast::<MonoObject>(),
161 )
162 };
163 let exc = unsafe { Exception::from_ptr(exc.cast()) };
164 #[cfg(feature = "referneced_objects")]
165 gc_unsafe_exit(marker);
166 exc.map_or_else(|| Ok(res), Err)
167 }
168}
169use crate::exception::Exception;
170impl ObjectTrait for Object {
171 ///Gets internal [`MonoObject`] pointer.
172 fn get_ptr(&self) -> *mut MonoObject {
173 #[cfg(not(feature = "referneced_objects"))]
174 {
175 self.obj_ptr
176 }
177 #[cfg(feature = "referneced_objects")]
178 {
179 self.handle.get_target()
180 }
181 }
182 unsafe fn from_ptr_unchecked(obj_ptr: *mut MonoObject) -> Self {
183 debug_assert!(
184 !obj_ptr.is_null(),
185 "Error: Violated function contract. *obj_ptr* must never be null, but was null."
186 );
187 #[cfg(not(feature = "referneced_objects"))]
188 {
189 Self { obj_ptr }
190 }
191 #[cfg(feature = "referneced_objects")]
192 {
193 Self {
194 handle: GCHandle::create_default(obj_ptr),
195 }
196 }
197 }
198}
199use crate::interop::InteropBox;
200impl Object {
201 ///Allocates new object of [`Class`] class. **Does not call the constructor**, to call constuctor call the `.ctor` method after creating the object.
202 /// # Examples
203 /// ```no_run
204 /// # use wrapped_mono::*;
205 /// # let domain = Domain::get_current().unwrap();
206 /// # let class = Class::get_void();
207 /// let new_obj = Object::new(&domain,&class);
208 /// ```
209 #[must_use]
210 pub fn new(domain: &crate::domain::Domain, class: &Class) -> Self {
211 #[cfg(feature = "referneced_objects")]
212 let marker = gc_unsafe_enter();
213 let obj = unsafe {
214 Self::from_ptr(crate::binds::mono_object_new(
215 domain.get_ptr(),
216 class.get_ptr(),
217 ))
218 }
219 .expect("Could not create new type from class!");
220 #[cfg(feature = "referneced_objects")]
221 gc_unsafe_exit(marker);
222 obj
223 }
224 /// Creates new [`Object`] from pointer *`obj_ptr`*. Checks if it is null, and returns [`None`] if so.
225 /// # Safety
226 /// *`obj_ptr`* must be either a valid [`MonoObject`] pointer or null, otherwise resulting [`Object`] will not be valid and will **cause crashes**.
227 #[must_use]
228 pub unsafe fn from_ptr(obj_ptr: *mut MonoObject) -> Option<Self> {
229 #[cfg(not(feature = "referneced_objects"))]
230 {
231 if obj_ptr.is_null() {
232 return None;
233 }
234 Some(Self { obj_ptr })
235 }
236 #[cfg(feature = "referneced_objects")]
237 {
238 if obj_ptr.is_null() {
239 return None;
240 }
241 Some(Self {
242 handle: GCHandle::create_default(obj_ptr),
243 })
244 }
245 }
246 /// Unboxes the value in [`Object`] `self`.
247 /// # Safety
248 /// Calling it on a type which can't be unboxed **will lead to a crash**.
249 /// # Panics
250 /// Type T must match the unboxed managed type.
251 /// Unboxing type
252 ///C#<br>
253 ///```ignore
254 ///int num = 123;
255 ///Object boxed = num;
256 ///RustFunction(boxed);
257 ///```
258 ///Rust
259 ///```no_run
260 /// # use wrapped_mono::*;
261 ///#[invokable]
262 ///fn rust_function(o:Object){
263 /// let val = o.unbox::<i32>();
264 ///}
265 ///```
266 #[must_use]
267 pub fn unbox<T: InteropBox + Copy>(&self) -> T {
268 #[cfg(not(feature = "unsafe_boxing"))]
269 {
270 let self_class = self.get_class();
271 let t_class = <T as InteropClass>::get_mono_class();
272 assert!(
273 self_class == t_class,
274 "tried to unbox class of type `{}` as type `{}`",
275 &self_class.get_name(),
276 &t_class.get_name()
277 );
278 }
279 #[cfg(feature = "referneced_objects")]
280 let marker = gc_unsafe_enter();
281 let ptr = unsafe {
282 crate::binds::mono_object_unbox(self.get_ptr())
283 .cast::<<T as InteropRecive>::SourceType>()
284 };
285 let res = T::get_rust_rep(unsafe { *ptr });
286 #[cfg(feature = "referneced_objects")]
287 gc_unsafe_exit(marker);
288 res
289 }
290 unsafe fn box_val_unsafe(
291 domain: &crate::domain::Domain,
292 class: &Class,
293 val: *mut std::ffi::c_void,
294 ) -> Self {
295 #[cfg(feature = "referneced_objects")]
296 let marker = gc_unsafe_enter();
297 let res = Self::from_ptr(crate::binds::mono_value_box(
298 domain.get_ptr(),
299 class.get_ptr(),
300 val,
301 ))
302 .expect("Could not box value");
303 #[cfg(feature = "referneced_objects")]
304 gc_unsafe_exit(marker);
305 res
306 }
307 /// Boxes value into an object.
308 /// # Examples
309 ///```no_run
310 /// # use wrapped_mono::*;
311 /// # let domain = Domain::get_current().unwrap();
312 /// let mut val:i32 = 0;
313 /// let obj = Object::box_val::<i32>(&domain,val); //New object of type `Int32?`
314 ///```
315 pub fn box_val<T: InteropBox>(domain: &Domain, mut data: T) -> Self {
316 let data = <T as InteropSend>::get_ffi_ptr(&mut data);
317 let class = T::get_mono_class();
318 unsafe { Self::box_val_unsafe(domain, &class, data) }
319 }
320 ///Gets an implementation virtual [`Method`] *`method`* for a specific [`Object`] *`obj`*.<br>
321 /// # Explanation
322 /// with given C# code
323 ///```ignore
324 /// class ParrentClass{
325 /// virtual void SomeMehod(){
326 /// //SomeFunction
327 /// }
328 /// }
329 /// class ChildClass : ParrentClass{
330 /// override void SomeMehod(){
331 /// ///SomeOtherFunction
332 /// }
333 /// }
334 ///```
335 /// When you call`get_vitual_method` on object that is instance of **`ChildClass`**
336 /// and method **`ParrentClass::SomeMethod`** you will get return value of **`ChildClass::SomeMethod`**.
337 #[must_use]
338 pub fn get_virtual_method<T: TupleToFFIPtrs + CompareClasses + InteropSend>(
339 obj: &Self,
340 method: &Method<T>,
341 ) -> Option<Method<T>> {
342 #[cfg(feature = "referneced_objects")]
343 let marker = gc_unsafe_enter();
344 let res = unsafe {
345 Method::from_ptr(crate::binds::mono_object_get_virtual_method(
346 obj.get_ptr(),
347 method.get_ptr(),
348 ))
349 };
350 #[cfg(feature = "referneced_objects")]
351 gc_unsafe_exit(marker);
352 res
353 }
354}
355impl Object {
356 ///Clones the underlying [`MonoObject`] *not* the reference to this object. (e.g when called on a reference to a managed object A will create second object B, not another reference to object A).
357 #[must_use]
358 pub fn clone_managed_object(&self) -> Self {
359 //if clone fails, it means that there is a much bigger problem somewhere down the line, so it can be just ignored.
360 #[cfg(feature = "referneced_objects")]
361 let marker = gc_unsafe_enter();
362 let res = unsafe { Self::from_ptr(crate::binds::mono_object_clone(self.get_ptr())) }
363 .expect("MonoRuntime could not clone object!");
364 #[cfg(feature = "referneced_objects")]
365 gc_unsafe_exit(marker);
366 res
367 }
368}
369//for 0.2 TODO:extend functionalities relating to properties.
370use crate::interop::InteropClass;
371impl InteropClass for Object {
372 fn get_mono_class() -> Class {
373 Class::get_object()
374 }
375}
376impl InteropClass for Option<Object> {
377 fn get_mono_class() -> Class {
378 Class::get_object()
379 }
380}
381impl<O: ObjectTrait> PartialEq<O> for Object {
382 fn eq(&self, other: &O) -> bool {
383 self.get_ptr() == other.get_ptr()
384 }
385}
386impl Clone for Object {
387 fn clone(&self) -> Self {
388 unsafe { Self::from_ptr(self.get_ptr()).unwrap() } //If object exists then it can't be null
389 }
390}