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}