metacall/types/
metacall_pointer.rs

1use super::MetaCallValue;
2use crate::{
3    bindings::{metacall_value_create_ptr, metacall_value_destroy, metacall_value_to_ptr},
4    MetaCallNull,
5};
6use std::{
7    ffi::c_void,
8    fmt::{self, Debug, Formatter},
9};
10
11/// Represents MetaCall pointer. This type cannot be used in other languages. This type is highly
12/// unsafe so be careful!
13pub struct MetaCallPointer {
14    leak: bool,
15    rust_value: *mut Box<dyn MetaCallValue>,
16    rust_value_leak: bool,
17    value: *mut c_void,
18}
19unsafe impl Send for MetaCallPointer {}
20unsafe impl Sync for MetaCallPointer {}
21impl Clone for MetaCallPointer {
22    fn clone(&self) -> Self {
23        Self {
24            leak: true,
25            rust_value: self.rust_value,
26            rust_value_leak: true,
27            value: self.value,
28        }
29    }
30}
31impl Debug for MetaCallPointer {
32    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
33        let boxed_value = unsafe { Box::from_raw(self.rust_value) };
34        let value = if (*boxed_value).is::<MetaCallNull>() {
35            None
36        } else {
37            Some(format!("{:#?}", boxed_value))
38        };
39        Box::leak(boxed_value);
40
41        f.debug_struct("MetaCallPointer")
42            .field("value", &value)
43            .finish()
44    }
45}
46
47impl MetaCallPointer {
48    fn get_rust_value_ptr(value: *mut c_void) -> *mut Box<dyn MetaCallValue> {
49        unsafe { metacall_value_to_ptr(value) as *mut Box<dyn MetaCallValue> }
50    }
51
52    #[doc(hidden)]
53    pub fn new_raw(value: *mut c_void) -> Result<Self, Box<dyn MetaCallValue>> {
54        Ok(Self {
55            leak: false,
56            rust_value: Self::get_rust_value_ptr(value),
57            rust_value_leak: false,
58            value,
59        })
60    }
61
62    #[doc(hidden)]
63    pub fn new_raw_leak(value: *mut c_void) -> Result<Self, Box<dyn MetaCallValue>> {
64        Ok(Self {
65            leak: true,
66            rust_value: Self::get_rust_value_ptr(value),
67            rust_value_leak: false,
68            value,
69        })
70    }
71
72    /// Creates a new MetaCall pointer and casts it to T.
73    pub fn new(ptr: impl MetaCallValue) -> Self {
74        let rust_value = Box::into_raw(Box::new(Box::new(ptr) as Box<dyn MetaCallValue>));
75
76        Self {
77            leak: false,
78            rust_value,
79            rust_value_leak: false,
80            value: unsafe { metacall_value_create_ptr(rust_value.cast()) },
81        }
82    }
83
84    /// Consumes the MetaCall pointer and returns ownership of the value without type
85    /// casting([MetaCallValue](MetaCallValue)).
86    pub fn get_value_untyped(mut self) -> Box<dyn MetaCallValue> {
87        self.rust_value_leak = true;
88
89        unsafe { *Box::from_raw(self.rust_value) }
90    }
91    /// Consumes the MetaCall pointer and returns ownership of the value.
92    pub fn get_value<T: MetaCallValue>(self) -> Result<T, Box<dyn MetaCallValue>> {
93        match self.get_value_untyped().downcast::<T>() {
94            Ok(rust_value) => Ok(rust_value),
95            Err(original) => Err(original),
96        }
97    }
98
99    #[doc(hidden)]
100    pub fn into_raw(mut self) -> *mut c_void {
101        self.leak = true;
102        self.rust_value_leak = true;
103
104        self.value
105    }
106}
107
108impl Drop for MetaCallPointer {
109    fn drop(&mut self) {
110        if !self.leak {
111            unsafe { metacall_value_destroy(self.value) }
112        }
113
114        if !self.rust_value_leak {
115            unsafe { drop(Box::from_raw(self.rust_value)) }
116        }
117    }
118}