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}