1use alloc::string::String;
7use core::fmt;
8
9pub(crate) const JSIDX_OFFSET: u64 = 128;
12
13pub(crate) const JSIDX_UNDEFINED: u64 = JSIDX_OFFSET;
15
16pub(crate) const JSIDX_NULL: u64 = JSIDX_OFFSET + 1;
18
19pub(crate) const JSIDX_TRUE: u64 = JSIDX_OFFSET + 2;
21
22pub(crate) const JSIDX_FALSE: u64 = JSIDX_OFFSET + 3;
24
25pub(crate) const JSIDX_RESERVED: u64 = JSIDX_OFFSET + 4;
27
28pub struct JsValue {
40 #[doc(hidden)]
41 pub idx: u64,
42}
43
44impl JsValue {
45 pub const NULL: JsValue = JsValue::_new(JSIDX_NULL);
47
48 pub const UNDEFINED: JsValue = JsValue::_new(JSIDX_UNDEFINED);
50
51 pub const TRUE: JsValue = JsValue::_new(JSIDX_TRUE);
53
54 pub const FALSE: JsValue = JsValue::_new(JSIDX_FALSE);
56
57 #[inline]
59 const fn _new(idx: u64) -> JsValue {
60 JsValue { idx }
61 }
62
63 #[inline]
67 pub(crate) fn from_id(id: u64) -> Self {
68 Self { idx: id }
69 }
70
71 #[inline]
75 pub fn id(&self) -> u64 {
76 self.idx
77 }
78
79 #[inline]
82 pub fn unchecked_into_f64(&self) -> f64 {
83 self.as_f64().unwrap_or(f64::NAN)
84 }
85
86 #[inline]
88 pub fn has_type<T: crate::JsCast>(&self) -> bool {
89 T::is_type_of(self)
90 }
91
92 #[inline]
96 pub fn into_abi(self) -> u32 {
97 let id = self.idx;
98 core::mem::forget(self);
99 id as u32
100 }
101
102 #[inline]
104 pub const fn undefined() -> JsValue {
105 JsValue::UNDEFINED
106 }
107
108 #[inline]
110 pub const fn null() -> JsValue {
111 JsValue::NULL
112 }
113
114 #[inline]
116 pub const fn from_bool(b: bool) -> JsValue {
117 if b { JsValue::TRUE } else { JsValue::FALSE }
118 }
119
120 #[allow(clippy::should_implement_trait)]
122 pub fn from_str(s: &str) -> JsValue {
123 s.into()
124 }
125
126 pub fn from_f64(n: f64) -> JsValue {
128 n.into()
129 }
130}
131
132impl Clone for JsValue {
133 #[inline]
134 fn clone(&self) -> JsValue {
135 if self.idx < JSIDX_RESERVED {
137 return JsValue { idx: self.idx };
138 }
139
140 crate::js_helpers::js_clone_heap_ref(self.idx)
142 }
143}
144
145impl Drop for JsValue {
146 #[inline]
147 fn drop(&mut self) {
148 if self.idx < JSIDX_RESERVED {
150 return;
151 }
152
153 crate::batch::queue_js_drop(self.idx);
155 }
156}
157
158impl PartialEq<&str> for JsValue {
159 fn eq(&self, other: &&str) -> bool {
160 match self.as_string() {
161 Some(s) => &s == other,
162 None => false,
163 }
164 }
165}
166
167impl PartialEq<JsValue> for &str {
168 fn eq(&self, other: &JsValue) -> bool {
169 match other.as_string() {
170 Some(s) => self == &s,
171 None => false,
172 }
173 }
174}
175
176impl PartialEq<str> for JsValue {
177 fn eq(&self, other: &str) -> bool {
178 match self.as_string() {
179 Some(s) => s == other,
180 None => false,
181 }
182 }
183}
184
185impl PartialEq<String> for JsValue {
186 fn eq(&self, other: &String) -> bool {
187 match self.as_string() {
188 Some(s) => &s == other,
189 None => false,
190 }
191 }
192}
193
194impl PartialEq<JsValue> for String {
195 fn eq(&self, other: &JsValue) -> bool {
196 match other.as_string() {
197 Some(s) => self == &s,
198 None => false,
199 }
200 }
201}
202
203impl PartialEq<&String> for JsValue {
204 fn eq(&self, other: &&String) -> bool {
205 match self.as_string() {
206 Some(s) => &s == *other,
207 None => false,
208 }
209 }
210}
211
212impl PartialEq<JsValue> for &String {
213 fn eq(&self, other: &JsValue) -> bool {
214 match other.as_string() {
215 Some(s) => *self == &s,
216 None => false,
217 }
218 }
219}
220
221impl PartialEq<bool> for JsValue {
222 fn eq(&self, other: &bool) -> bool {
223 match self.as_bool() {
224 Some(b) => b == *other,
225 None => false,
226 }
227 }
228}
229
230impl PartialEq<JsValue> for bool {
231 fn eq(&self, other: &JsValue) -> bool {
232 match other.as_bool() {
233 Some(b) => *self == b,
234 None => false,
235 }
236 }
237}
238
239impl PartialEq<f32> for JsValue {
240 fn eq(&self, other: &f32) -> bool {
241 match self.as_f64() {
242 Some(n) => n == (*other as f64),
243 None => false,
244 }
245 }
246}
247
248impl PartialEq<JsValue> for f32 {
249 fn eq(&self, other: &JsValue) -> bool {
250 match other.as_f64() {
251 Some(n) => (*self as f64) == n,
252 None => false,
253 }
254 }
255}
256
257impl PartialEq<f64> for JsValue {
258 fn eq(&self, other: &f64) -> bool {
259 match self.as_f64() {
260 Some(n) => n == *other,
261 None => false,
262 }
263 }
264}
265
266impl PartialEq<JsValue> for f64 {
267 fn eq(&self, other: &JsValue) -> bool {
268 match other.as_f64() {
269 Some(n) => *self == n,
270 None => false,
271 }
272 }
273}
274
275macro_rules! impl_partial_eq_int {
277 ($($t:ty),*) => {
278 $(
279 impl PartialEq<$t> for JsValue {
280 fn eq(&self, other: &$t) -> bool {
281 match self.as_f64() {
282 Some(n) => n == (*other as f64),
283 None => false,
284 }
285 }
286 }
287
288 impl PartialEq<JsValue> for $t {
289 fn eq(&self, other: &JsValue) -> bool {
290 match other.as_f64() {
291 Some(n) => (*self as f64) == n,
292 None => false,
293 }
294 }
295 }
296 )*
297 };
298}
299
300impl_partial_eq_int!(
301 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
302);
303
304impl fmt::Debug for JsValue {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 f.write_str(&self.as_debug_string())
307 }
308}
309
310impl PartialEq for JsValue {
311 fn eq(&self, other: &Self) -> bool {
312 self.idx == other.idx
313 }
314}
315
316impl Eq for JsValue {}
317
318impl core::hash::Hash for JsValue {
319 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
320 self.idx.hash(state);
321 }
322}
323
324impl Default for JsValue {
325 fn default() -> Self {
326 Self::UNDEFINED
327 }
328}
329
330impl JsValue {
332 pub fn checked_div(&self, rhs: &JsValue) -> JsValue {
334 crate::js_helpers::js_checked_div(self, rhs)
335 }
336
337 pub fn pow(&self, rhs: &JsValue) -> JsValue {
339 crate::js_helpers::js_pow(self, rhs)
340 }
341
342 pub fn bit_and(&self, rhs: &JsValue) -> JsValue {
344 crate::js_helpers::js_bit_and(self, rhs)
345 }
346
347 pub fn bit_or(&self, rhs: &JsValue) -> JsValue {
349 crate::js_helpers::js_bit_or(self, rhs)
350 }
351
352 pub fn bit_xor(&self, rhs: &JsValue) -> JsValue {
354 crate::js_helpers::js_bit_xor(self, rhs)
355 }
356
357 pub fn bit_not(&self) -> JsValue {
359 crate::js_helpers::js_bit_not(self)
360 }
361
362 pub fn shl(&self, rhs: &JsValue) -> JsValue {
364 crate::js_helpers::js_shl(self, rhs)
365 }
366
367 pub fn shr(&self, rhs: &JsValue) -> JsValue {
369 crate::js_helpers::js_shr(self, rhs)
370 }
371
372 pub fn unsigned_shr(&self, rhs: &JsValue) -> u32 {
374 crate::js_helpers::js_unsigned_shr(self, rhs)
375 }
376
377 pub fn add(&self, rhs: &JsValue) -> JsValue {
379 crate::js_helpers::js_add(self, rhs)
380 }
381
382 pub fn sub(&self, rhs: &JsValue) -> JsValue {
384 crate::js_helpers::js_sub(self, rhs)
385 }
386
387 pub fn mul(&self, rhs: &JsValue) -> JsValue {
389 crate::js_helpers::js_mul(self, rhs)
390 }
391
392 pub fn div(&self, rhs: &JsValue) -> JsValue {
394 crate::js_helpers::js_div(self, rhs)
395 }
396
397 pub fn rem(&self, rhs: &JsValue) -> JsValue {
399 crate::js_helpers::js_rem(self, rhs)
400 }
401
402 pub fn neg(&self) -> JsValue {
404 crate::js_helpers::js_neg(self)
405 }
406
407 pub fn lt(&self, rhs: &JsValue) -> bool {
409 crate::js_helpers::js_lt(self, rhs)
410 }
411
412 pub fn le(&self, rhs: &JsValue) -> bool {
414 crate::js_helpers::js_le(self, rhs)
415 }
416
417 pub fn gt(&self, rhs: &JsValue) -> bool {
419 crate::js_helpers::js_gt(self, rhs)
420 }
421
422 pub fn ge(&self, rhs: &JsValue) -> bool {
424 crate::js_helpers::js_ge(self, rhs)
425 }
426
427 pub fn loose_eq(&self, rhs: &JsValue) -> bool {
429 crate::js_helpers::js_loose_eq(self, rhs)
430 }
431
432 pub fn is_falsy(&self) -> bool {
434 crate::js_helpers::js_is_falsy(self)
435 }
436
437 pub fn is_truthy(&self) -> bool {
439 crate::js_helpers::js_is_truthy(self)
440 }
441
442 pub fn is_object(&self) -> bool {
444 crate::js_helpers::js_is_object(self)
445 }
446
447 pub fn is_function(&self) -> bool {
449 crate::js_helpers::js_is_function(self)
450 }
451
452 pub fn is_string(&self) -> bool {
454 crate::js_helpers::js_is_string(self)
455 }
456
457 pub fn is_symbol(&self) -> bool {
459 crate::js_helpers::js_is_symbol(self)
460 }
461
462 pub fn is_bigint(&self) -> bool {
464 crate::js_helpers::js_is_bigint(self)
465 }
466
467 pub fn is_undefined(&self) -> bool {
469 if self.idx == JSIDX_UNDEFINED {
470 return true;
471 }
472 crate::js_helpers::js_is_undefined(self)
473 }
474
475 pub fn is_null(&self) -> bool {
477 if self.idx == JSIDX_NULL {
478 return true;
479 }
480 crate::js_helpers::js_is_null(self)
481 }
482
483 pub fn js_typeof(&self) -> JsValue {
485 crate::js_helpers::js_typeof(self)
486 }
487
488 pub fn js_in(&self, obj: &JsValue) -> bool {
490 crate::js_helpers::js_in(self, obj)
491 }
492
493 pub fn as_bool(&self) -> Option<bool> {
495 match self.idx {
496 JSIDX_TRUE => Some(true),
497 JSIDX_FALSE => Some(false),
498 idx if idx < JSIDX_RESERVED => None,
499 _ => {
500 if crate::js_helpers::js_is_true(self) {
502 Some(true)
503 } else if crate::js_helpers::js_is_false(self) {
504 Some(false)
505 } else {
506 None
507 }
508 }
509 }
510 }
511
512 pub fn as_f64(&self) -> Option<f64> {
514 crate::js_helpers::js_as_f64(self)
515 }
516
517 pub fn as_string(&self) -> Option<String> {
519 crate::js_helpers::js_as_string(self)
520 }
521
522 pub fn as_debug_string(&self) -> String {
524 crate::js_helpers::js_debug_string(self)
525 }
526}
527
528use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub};
530
531impl Neg for &JsValue {
532 type Output = JsValue;
533 fn neg(self) -> JsValue {
534 JsValue::neg(self)
535 }
536}
537
538impl Not for &JsValue {
539 type Output = bool;
540
541 fn not(self) -> Self::Output {
542 JsValue::is_falsy(self)
543 }
544}
545
546impl BitAnd<&JsValue> for &JsValue {
547 type Output = JsValue;
548 fn bitand(self, rhs: &JsValue) -> JsValue {
549 JsValue::bit_and(self, rhs)
550 }
551}
552
553impl BitOr<&JsValue> for &JsValue {
554 type Output = JsValue;
555 fn bitor(self, rhs: &JsValue) -> JsValue {
556 JsValue::bit_or(self, rhs)
557 }
558}
559
560impl BitXor<&JsValue> for &JsValue {
561 type Output = JsValue;
562 fn bitxor(self, rhs: &JsValue) -> JsValue {
563 JsValue::bit_xor(self, rhs)
564 }
565}
566
567impl Shl<&JsValue> for &JsValue {
568 type Output = JsValue;
569 fn shl(self, rhs: &JsValue) -> JsValue {
570 JsValue::shl(self, rhs)
571 }
572}
573
574impl Shr<&JsValue> for &JsValue {
575 type Output = JsValue;
576 fn shr(self, rhs: &JsValue) -> JsValue {
577 JsValue::shr(self, rhs)
578 }
579}
580
581impl Add<&JsValue> for &JsValue {
582 type Output = JsValue;
583 fn add(self, rhs: &JsValue) -> JsValue {
584 JsValue::add(self, rhs)
585 }
586}
587
588impl Sub<&JsValue> for &JsValue {
589 type Output = JsValue;
590 fn sub(self, rhs: &JsValue) -> JsValue {
591 JsValue::sub(self, rhs)
592 }
593}
594
595impl Mul<&JsValue> for &JsValue {
596 type Output = JsValue;
597 fn mul(self, rhs: &JsValue) -> JsValue {
598 JsValue::mul(self, rhs)
599 }
600}
601
602impl Div<&JsValue> for &JsValue {
603 type Output = JsValue;
604 fn div(self, rhs: &JsValue) -> JsValue {
605 JsValue::div(self, rhs)
606 }
607}
608
609impl Rem<&JsValue> for &JsValue {
610 type Output = JsValue;
611 fn rem(self, rhs: &JsValue) -> JsValue {
612 JsValue::rem(self, rhs)
613 }
614}
615
616impl Neg for JsValue {
617 type Output = JsValue;
618 fn neg(self) -> JsValue {
619 JsValue::neg(&self)
620 }
621}
622
623impl Not for JsValue {
624 type Output = bool;
625 fn not(self) -> Self::Output {
626 JsValue::is_falsy(&self)
627 }
628}
629
630macro_rules! impl_binary_op {
632 ($trait:ident, $method:ident, $js_method:ident) => {
633 impl $trait for JsValue {
635 type Output = JsValue;
636 fn $method(self, rhs: JsValue) -> JsValue {
637 JsValue::$js_method(&self, &rhs)
638 }
639 }
640
641 impl $trait<&JsValue> for JsValue {
643 type Output = JsValue;
644 fn $method(self, rhs: &JsValue) -> JsValue {
645 JsValue::$js_method(&self, rhs)
646 }
647 }
648
649 impl<'a> $trait<JsValue> for &'a JsValue {
651 type Output = JsValue;
652 fn $method(self, rhs: JsValue) -> JsValue {
653 JsValue::$js_method(self, &rhs)
654 }
655 }
656 };
657}
658
659impl_binary_op!(Add, add, add);
660impl_binary_op!(Sub, sub, sub);
661impl_binary_op!(Mul, mul, mul);
662impl_binary_op!(Div, div, div);
663impl_binary_op!(Rem, rem, rem);
664impl_binary_op!(BitAnd, bitand, bit_and);
665impl_binary_op!(BitOr, bitor, bit_or);
666impl_binary_op!(BitXor, bitxor, bit_xor);
667impl_binary_op!(Shl, shl, shl);
668impl_binary_op!(Shr, shr, shr);
669
670impl From<bool> for JsValue {
671 fn from(val: bool) -> Self {
672 JsValue::from_bool(val)
673 }
674}