1use crate::mem::{block::Block, manager::Dealloc, optional_ref::OptionalRef};
2
3use super::{
4 any_cast::AnyCast,
5 any_internal::AnyInternal,
6 bitset::{ref_type, REF_SUBSET_SUPERPOSITION},
7 js_array::JsArrayRef,
8 js_object::JsObjectRef,
9 null::Null,
10 ref_cast::RefCast,
11 type_::Type,
12};
13
14pub type Any<D> = OptionalRef<AnyInternal<D>>;
15
16impl<D: Dealloc> Any<D> {
17 #[inline(always)]
18 unsafe fn u64(&self) -> u64 {
19 self.internal().0
20 }
21 #[inline(always)]
22 pub fn is<T: AnyCast<D>>(&self) -> bool {
23 unsafe { T::has_same_type(self.u64()) }
24 }
25 pub fn move_from<T: AnyCast<D>>(t: T) -> Self {
41 t.move_to_any()
42 }
43 #[allow(clippy::result_unit_err)]
44 pub fn try_move<T: AnyCast<D>>(self) -> Result<T, ()> {
45 if self.is::<T>() {
46 return Ok(unsafe { T::from_any_internal(self.move_to_internal().0) });
47 }
48 Err(())
49 }
50 pub fn get_type(&self) -> Type {
52 if self.is_ref() {
53 match ref_type(unsafe { self.internal().0 }) {
54 0b00 => Type::String,
55 0b01 => Type::Object,
56 0b10 => Type::Array,
57 0b11 => Type::Bigint,
58 _ => unreachable!(),
59 }
60 } else if self.is::<f64>() {
61 Type::Number
62 } else if self.is::<Null>() {
63 Type::Null
64 } else {
65 Type::Bool
66 }
67 }
68 #[allow(clippy::result_unit_err)]
84 #[inline(always)]
85 pub fn try_ref<T: RefCast<D>>(&self) -> Result<&Block<T, D>, ()> {
86 let v = unsafe { self.u64() };
87 if T::REF_SUBSET.has(v) {
88 let p = (v & REF_SUBSET_SUPERPOSITION) as *const Block<T, D>;
89 return Ok(unsafe { &*p });
90 }
91 Err(())
92 }
93
94 pub fn for_each<E>(
97 &self,
98 mut f: impl FnMut(Any<D>, &Any<D>) -> Result<(), E>,
99 ) -> Result<(), E> {
100 match self.get_type() {
101 Type::Object => {
102 let o = self.clone().try_move::<JsObjectRef<D>>().unwrap();
103 for (k, v) in o.items() {
104 f(k.clone().move_to_any(), v)?;
105 }
106 }
107 Type::Array => {
108 let o = self.clone().try_move::<JsArrayRef<D>>().unwrap();
109 for (k, v) in o.items().iter().enumerate() {
110 f((k as f64).move_to_any(), v)?;
111 }
112 }
113 _ => {}
114 };
115 Ok(())
116 }
117}
118
119#[cfg(test)]
120mod test {
121 use std::{collections::HashSet, rc::Rc};
122
123 use wasm_bindgen_test::wasm_bindgen_test;
124
125 use crate::{
126 js::{
127 js_array::{new_array, JsArrayRef},
128 js_bigint::{new_bigint, JsBigintRef, Sign},
129 js_object::{new_object, JsObjectRef},
130 js_string::{new_string, JsString, JsStringRef},
131 null::Null,
132 },
133 mem::global::Global,
134 };
135
136 use super::*;
137
138 #[test]
139 #[wasm_bindgen_test]
140 fn test_unsized() {
141 let _x: Rc<[u8]> = Rc::new([1, 3]);
142 }
147
148 #[test]
149 #[wasm_bindgen_test]
150 fn test_number() {
151 type A = Any<Global>;
152 assert_eq!(A::move_from(1.0).try_move(), Ok(1.0));
153 let x: A = A::move_from(-1.0);
154 assert_eq!(x.try_move(), Ok(-1.0));
155 assert_eq!(A::move_from(f64::INFINITY).try_move(), Ok(f64::INFINITY));
156 assert_eq!(
157 A::move_from(f64::NEG_INFINITY).try_move(),
158 Ok(f64::NEG_INFINITY)
159 );
160 assert!(A::move_from(f64::NAN).try_move::<f64>().unwrap().is_nan());
161 assert_eq!(A::move_from(true).try_move::<f64>(), Err(()));
163 assert_eq!(A::move_from(Null()).try_move::<f64>(), Err(()));
164 }
165
166 #[test]
167 #[wasm_bindgen_test]
168 fn test_bool() {
169 type A = Any<Global>;
170 assert_eq!(A::move_from(true).try_move(), Ok(true));
171 assert_eq!(A::move_from(false).try_move(), Ok(false));
172 assert_eq!(A::move_from(15.0).try_move::<bool>(), Err(()));
174 assert_eq!(A::move_from(Null()).try_move::<bool>(), Err(()));
175 }
176
177 #[test]
178 #[wasm_bindgen_test]
179 fn test_null() {
180 type A = Any<Global>;
181 assert!(A::move_from(Null()).is::<Null>());
182 assert!(!A::move_from(-15.7).is::<Null>());
184 assert!(!A::move_from(false).is::<Null>());
185 }
186
187 #[test]
188 #[wasm_bindgen_test]
189 fn test_type() {
190 type A = Any<Global>;
191 assert_eq!(A::move_from(15.0).get_type(), Type::Number);
192 assert_eq!(A::move_from(true).get_type(), Type::Bool);
193 assert_eq!(A::move_from(Null()).get_type(), Type::Null);
194 }
195
196 #[test]
197 #[wasm_bindgen_test]
198 fn test_string() {
199 type A = Any<Global>;
200 type StringRef = JsStringRef<Global>;
201 let sm = new_string(Global(), []);
202 let s = sm.to_ref();
203 assert!(A::move_from(s.clone()).is::<StringRef>());
204 let v = s.items();
205 assert!(v.is_empty());
206
207 assert!(!A::move_from(15.0).is::<StringRef>());
209 assert!(!A::move_from(true).is::<StringRef>());
210 assert!(!A::move_from(Null()).is::<StringRef>());
211
212 let s = new_string(Global(), [0x20, 0x21]).to_ref();
213 assert!(A::move_from(s.clone()).is::<StringRef>());
214 let v = s.items();
215 assert_eq!(v, [0x20, 0x21]);
216 let u = A::move_from(s);
217 {
218 let s = u.try_ref::<JsString>().unwrap();
219 let items = s.object().items();
220 assert_eq!(items, [0x20, 0x21]);
221 }
222 let s = u.try_move::<StringRef>().unwrap();
223 let items = s.items();
224 assert_eq!(items, [0x20, 0x21]);
225 }
226
227 #[test]
228 #[wasm_bindgen_test]
229 fn test_object() {
230 type A = Any<Global>;
231 type ObjectRef = JsObjectRef<Global>;
232 assert!(!A::move_from(Null()).is::<ObjectRef>());
233
234 let o: ObjectRef = new_object(Global(), []).to_ref();
235 assert!(A::move_from(o.clone()).is::<ObjectRef>());
236 let v = o.items();
237 assert!(v.is_empty());
238 assert!(!A::move_from(15.0).is::<ObjectRef>());
240 assert!(!A::move_from(true).is::<ObjectRef>());
241
242 let o: ObjectRef = new_object(Global(), []).to_ref();
243 let u = A::move_from(o);
244 assert_eq!(u.get_type(), Type::Object);
245 {
246 let o = u.try_move::<ObjectRef>().unwrap();
247 let items = o.items();
248 assert!(items.is_empty());
249 }
250 }
251
252 #[test]
253 #[wasm_bindgen_test]
254 fn test_array() {
255 type A = Any<Global>;
256 type ArrayRef = JsArrayRef<Global>;
257 assert!(!A::move_from(Null()).is::<ArrayRef>());
258
259 let o: ArrayRef = new_array(Global(), []).to_ref();
260 assert!(A::move_from(o.clone()).is::<ArrayRef>());
261 let v = o.items();
262 assert!(v.is_empty());
263 assert!(!A::move_from(15.0).is::<ArrayRef>());
265 assert!(!A::move_from(true).is::<ArrayRef>());
266
267 let o: ArrayRef = new_array(Global(), []).to_ref();
268 let u = A::move_from(o);
269 assert_eq!(u.get_type(), Type::Array);
270 {
271 let o = u.try_move::<ArrayRef>().unwrap();
272 let items = o.items();
273 assert!(items.is_empty());
274 }
275 }
276
277 #[test]
278 #[wasm_bindgen_test]
279 fn test_bigint() {
280 type A = Any<Global>;
281 type BigintRef = JsBigintRef<Global>;
282 assert!(!A::move_from(Null()).is::<BigintRef>());
283
284 let o: BigintRef = new_bigint(Global(), Sign::Positive, []).to_ref();
285 assert!(A::move_from(o.clone()).is::<BigintRef>());
286 let v = o.items();
287 assert!(v.is_empty());
288 assert!(!A::move_from(15.0).is::<BigintRef>());
290 assert!(!A::move_from(true).is::<BigintRef>());
291
292 let o: BigintRef = new_bigint(Global(), Sign::Positive, []).to_ref();
293 let u = A::move_from(o);
294 assert_eq!(u.get_type(), Type::Bigint);
295 {
296 let o = u.try_move::<BigintRef>().unwrap();
297 let items = o.items();
298 assert!(items.is_empty());
299 }
300 }
301
302 #[test]
303 #[wasm_bindgen_test]
304 fn test_eq() {
305 let mut v = HashSet::<Any<Global>>::new();
306 v.insert(Any::move_from(1.0));
307 }
308}