pen_ffi/
any.rs

1use crate::{import, Boolean, ByteString, Error, List, Number, TypeInformation};
2
3import!(pen_ffi_any_is_boolean, fn(any: Any) -> Boolean);
4import!(pen_ffi_any_is_error, fn(any: Any) -> Boolean);
5import!(pen_ffi_any_is_none, fn(any: Any) -> Boolean);
6import!(pen_ffi_any_is_list, fn(any: Any) -> Boolean);
7import!(pen_ffi_any_is_number, fn(any: Any) -> Boolean);
8import!(pen_ffi_any_is_string, fn(any: Any) -> Boolean);
9
10import!(pen_ffi_any_to_boolean, fn(any: Any) -> Boolean);
11import!(pen_ffi_any_to_error, fn(any: Any) -> Error);
12import!(pen_ffi_any_to_list, fn(any: Any) -> List);
13import!(pen_ffi_any_to_number, fn(any: Any) -> Number);
14import!(pen_ffi_any_to_string, fn(any: Any) -> ByteString);
15
16#[repr(C)]
17pub struct Any {
18    type_information: &'static TypeInformation,
19    payload: u64,
20}
21
22impl Any {
23    pub fn new(type_information: &'static TypeInformation, payload: u64) -> Self {
24        Self {
25            type_information,
26            payload,
27        }
28    }
29
30    pub fn type_information(&self) -> &'static TypeInformation {
31        self.type_information
32    }
33
34    pub fn payload(&self) -> &u64 {
35        &self.payload
36    }
37
38    pub fn is_boolean(&self) -> bool {
39        unsafe { pen_ffi_any_is_boolean(self.clone()) }.into()
40    }
41
42    pub fn is_error(&self) -> bool {
43        unsafe { pen_ffi_any_is_error(self.clone()) }.into()
44    }
45
46    pub fn is_none(&self) -> bool {
47        unsafe { pen_ffi_any_is_none(self.clone()) }.into()
48    }
49
50    pub fn is_list(&self) -> bool {
51        unsafe { pen_ffi_any_is_list(self.clone()) }.into()
52    }
53
54    pub fn is_number(&self) -> bool {
55        unsafe { pen_ffi_any_is_number(self.clone()) }.into()
56    }
57
58    pub fn is_string(&self) -> bool {
59        unsafe { pen_ffi_any_is_string(self.clone()) }.into()
60    }
61}
62
63impl Clone for Any {
64    fn clone(&self) -> Self {
65        Self {
66            type_information: self.type_information,
67            payload: (self.type_information.clone_fn())(self.payload),
68        }
69    }
70}
71
72impl Drop for Any {
73    fn drop(&mut self) {
74        (self.type_information.drop_fn())(self.payload);
75    }
76}
77
78impl TryFrom<Any> for Boolean {
79    type Error = ();
80
81    fn try_from(value: Any) -> Result<Self, ()> {
82        if value.is_boolean() {
83            Ok(unsafe { pen_ffi_any_to_boolean(value) })
84        } else {
85            Err(())
86        }
87    }
88}
89
90impl TryFrom<Any> for Error {
91    type Error = ();
92
93    fn try_from(value: Any) -> Result<Self, ()> {
94        if value.is_error() {
95            Ok(unsafe { pen_ffi_any_to_error(value) })
96        } else {
97            Err(())
98        }
99    }
100}
101
102impl TryFrom<Any> for List {
103    type Error = ();
104
105    fn try_from(value: Any) -> Result<Self, ()> {
106        if value.is_list() {
107            Ok(unsafe { pen_ffi_any_to_list(value) })
108        } else {
109            Err(())
110        }
111    }
112}
113
114impl TryFrom<Any> for Number {
115    type Error = ();
116
117    fn try_from(value: Any) -> Result<Self, ()> {
118        if value.is_number() {
119            Ok(unsafe { pen_ffi_any_to_number(value) })
120        } else {
121            Err(())
122        }
123    }
124}
125
126impl TryFrom<Any> for ByteString {
127    type Error = ();
128
129    fn try_from(value: Any) -> Result<Self, ()> {
130        if value.is_string() {
131            Ok(unsafe { pen_ffi_any_to_string(value) })
132        } else {
133            Err(())
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    mod box_ {
143        use super::*;
144        use alloc::boxed::Box;
145
146        #[pen_ffi_macro::any(crate = "crate")]
147        #[derive(Clone)]
148        pub struct TypeA {
149            #[allow(dead_code)]
150            value: Box<f64>,
151        }
152
153        #[pen_ffi_macro::any(crate = "crate")]
154        #[allow(clippy::redundant_allocation)]
155        #[derive(Clone)]
156        pub struct TypeB {
157            #[allow(dead_code)]
158            value: Box<Box<f64>>,
159        }
160
161        #[test]
162        fn drop_any() {
163            let _ = Any::from(TypeA {
164                value: Box::new(42.0),
165            });
166        }
167
168        #[test]
169        fn clone_any() {
170            let x = Any::from(TypeA {
171                value: Box::new(42.0),
172            });
173
174            drop(x.clone());
175            drop(x)
176        }
177
178        #[test]
179        fn as_inner() {
180            let x = Any::from(TypeA {
181                value: Box::new(42.0),
182            });
183
184            let _: &TypeA = (&x).try_into().unwrap();
185        }
186    }
187
188    mod rc {
189        use super::*;
190        use alloc::sync::Arc;
191
192        #[pen_ffi_macro::any(crate = "crate")]
193        #[derive(Clone)]
194        pub struct TypeA {
195            #[allow(dead_code)]
196            value: Arc<f64>,
197        }
198
199        #[pen_ffi_macro::any(crate = "crate")]
200        #[allow(clippy::redundant_allocation)]
201        #[derive(Clone)]
202        pub struct TypeB {
203            #[allow(dead_code)]
204            value: Arc<Arc<f64>>,
205        }
206
207        #[test]
208        fn drop_any() {
209            let _ = Any::from(TypeA {
210                value: Arc::new(42.0),
211            });
212        }
213
214        #[test]
215        fn clone_any() {
216            let x = Any::from(TypeA {
217                value: Arc::new(42.0),
218            });
219
220            drop(x.clone());
221            drop(x)
222        }
223
224        #[test]
225        fn as_inner() {
226            let x = Any::from(TypeA {
227                value: Arc::new(42.0),
228            });
229
230            let _: &TypeA = (&x).try_into().unwrap();
231        }
232    }
233
234    mod f64 {
235        use super::*;
236
237        #[pen_ffi_macro::any(crate = "crate")]
238        #[derive(Clone)]
239        pub struct Type {
240            #[allow(dead_code)]
241            value: f64,
242        }
243
244        #[test]
245        fn drop_any() {
246            let _ = Any::from(Type { value: 42.0 });
247        }
248
249        #[test]
250        fn clone_any() {
251            let x = Any::from(Type { value: 42.0 });
252
253            drop(x.clone());
254            drop(x)
255        }
256    }
257
258    mod send_sync {
259        use super::*;
260
261        #[pen_ffi_macro::any(crate = "crate")]
262        #[derive(Clone, Default)]
263        struct Dummy {}
264
265        fn drop_send_and_sync(_: impl Send + Sync) {}
266
267        #[test]
268        fn implement_send_and_sync() {
269            drop_send_and_sync(Any::from(Dummy::default()));
270        }
271    }
272}