1use alloc::{boxed::Box, string::String, vec::Vec};
7use core::fmt;
8use core::ptr::NonNull;
9
10pub(crate) const JSIDX_OFFSET: u64 = 128;
14
15pub(crate) const JSIDX_UNDEFINED: u64 = JSIDX_OFFSET;
17
18pub(crate) const JSIDX_NULL: u64 = JSIDX_OFFSET + 1;
20
21pub(crate) const JSIDX_TRUE: u64 = JSIDX_OFFSET + 2;
23
24pub(crate) const JSIDX_FALSE: u64 = JSIDX_OFFSET + 3;
26
27pub(crate) const JSIDX_RESERVED: u64 = JSIDX_OFFSET + 4;
30
31#[inline]
32fn is_special_value_id(id: u64) -> bool {
33 (JSIDX_OFFSET..JSIDX_RESERVED).contains(&id)
34}
35
36pub struct JsValue {
48 #[doc(hidden)]
52 pub idx: u64,
53}
54
55impl JsValue {
56 pub const NULL: JsValue = JsValue::_new(JSIDX_NULL);
58
59 pub const UNDEFINED: JsValue = JsValue::_new(JSIDX_UNDEFINED);
61
62 pub const TRUE: JsValue = JsValue::_new(JSIDX_TRUE);
64
65 pub const FALSE: JsValue = JsValue::_new(JSIDX_FALSE);
67
68 #[inline]
70 const fn _new(idx: u64) -> JsValue {
71 JsValue { idx }
72 }
73
74 #[inline]
78 pub(crate) fn from_id(id: u64) -> Self {
79 Self::_new(id)
80 }
81
82 #[inline]
86 pub fn id(&self) -> u64 {
87 self.idx
88 }
89
90 #[cfg(feature = "serde-serialize")]
102 #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` instead"]
103 pub fn from_serde<T>(t: &T) -> serde_json::Result<JsValue>
104 where
105 T: serde::ser::Serialize + ?Sized,
106 {
107 let json = serde_json::to_string(t)?;
108 Ok(crate::__wry_call_js_function!(
109 "(s) => JSON.parse(s)",
110 fn(&str) -> JsValue,
111 (json.as_str())
112 ))
113 }
114
115 #[cfg(feature = "serde-serialize")]
127 #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` instead"]
128 pub fn into_serde<T>(&self) -> serde_json::Result<T>
129 where
130 T: for<'a> serde::de::Deserialize<'a>,
131 {
132 let json: String = crate::__wry_call_js_function!(
135 "(v) => JSON.stringify(v) ?? \"null\"",
136 fn(JsValue) -> String,
137 (self.clone())
138 );
139 serde_json::from_str(&json)
140 }
141
142 #[inline]
145 pub fn unchecked_into_f64(&self) -> f64 {
146 self.as_f64().unwrap_or(f64::NAN)
147 }
148
149 #[inline]
151 pub fn has_type<T: crate::JsCast>(&self) -> bool {
152 T::is_type_of(self)
153 }
154
155 #[inline]
159 pub fn into_abi(self) -> u32 {
160 let id = self.idx;
161 core::mem::forget(self);
162 id as u32
163 }
164
165 #[inline]
167 pub const fn undefined() -> JsValue {
168 JsValue::UNDEFINED
169 }
170
171 #[inline]
173 pub const fn null() -> JsValue {
174 JsValue::NULL
175 }
176
177 #[inline]
179 pub const fn from_bool(b: bool) -> JsValue {
180 if b { JsValue::TRUE } else { JsValue::FALSE }
181 }
182
183 #[allow(clippy::should_implement_trait)]
185 pub fn from_str(s: &str) -> JsValue {
186 s.into()
187 }
188
189 pub fn from_f64(n: f64) -> JsValue {
191 n.into()
192 }
193
194 pub fn bigint_from_str(s: &str) -> JsValue {
196 crate::js_helpers::js_bigint_from_str(s)
197 }
198
199 pub fn symbol(description: Option<&str>) -> JsValue {
201 crate::js_helpers::js_symbol_new(description)
202 }
203}
204
205impl Clone for JsValue {
206 #[inline]
207 fn clone(&self) -> JsValue {
208 if is_special_value_id(self.idx) {
211 return JsValue::_new(self.idx);
212 }
213
214 crate::js_helpers::js_clone_heap_ref(self.idx)
216 }
217}
218
219impl Drop for JsValue {
220 #[inline]
221 fn drop(&mut self) {
222 if self.idx < JSIDX_RESERVED {
224 return;
225 }
226
227 crate::batch::queue_js_drop(self.idx);
229 }
230}
231
232impl<'a> PartialEq<&'a str> for JsValue {
233 fn eq(&self, other: &&'a str) -> bool {
234 match self.as_string() {
235 Some(s) => &s == other,
236 None => false,
237 }
238 }
239}
240
241impl PartialEq<JsValue> for &str {
242 fn eq(&self, other: &JsValue) -> bool {
243 match other.as_string() {
244 Some(s) => self == &s,
245 None => false,
246 }
247 }
248}
249
250impl PartialEq<str> for JsValue {
251 fn eq(&self, other: &str) -> bool {
252 match self.as_string() {
253 Some(s) => s == other,
254 None => false,
255 }
256 }
257}
258
259impl PartialEq<String> for JsValue {
260 fn eq(&self, other: &String) -> bool {
261 match self.as_string() {
262 Some(s) => &s == other,
263 None => false,
264 }
265 }
266}
267
268impl PartialEq<JsValue> for String {
269 fn eq(&self, other: &JsValue) -> bool {
270 match other.as_string() {
271 Some(s) => self == &s,
272 None => false,
273 }
274 }
275}
276
277impl<'a> PartialEq<&'a String> for JsValue {
278 fn eq(&self, other: &&'a String) -> bool {
279 match self.as_string() {
280 Some(s) => &s == *other,
281 None => false,
282 }
283 }
284}
285
286impl PartialEq<JsValue> for &String {
287 fn eq(&self, other: &JsValue) -> bool {
288 match other.as_string() {
289 Some(s) => *self == &s,
290 None => false,
291 }
292 }
293}
294
295impl PartialEq<bool> for JsValue {
296 fn eq(&self, other: &bool) -> bool {
297 match self.as_bool() {
298 Some(b) => b == *other,
299 None => false,
300 }
301 }
302}
303
304impl PartialEq<JsValue> for bool {
305 fn eq(&self, other: &JsValue) -> bool {
306 match other.as_bool() {
307 Some(b) => *self == b,
308 None => false,
309 }
310 }
311}
312
313impl PartialEq<f32> for JsValue {
314 fn eq(&self, other: &f32) -> bool {
315 match self.as_f64() {
316 Some(n) => n == (*other as f64),
317 None => false,
318 }
319 }
320}
321
322impl PartialEq<JsValue> for f32 {
323 fn eq(&self, other: &JsValue) -> bool {
324 match other.as_f64() {
325 Some(n) => (*self as f64) == n,
326 None => false,
327 }
328 }
329}
330
331impl PartialEq<f64> for JsValue {
332 fn eq(&self, other: &f64) -> bool {
333 match self.as_f64() {
334 Some(n) => n == *other,
335 None => false,
336 }
337 }
338}
339
340impl PartialEq<JsValue> for f64 {
341 fn eq(&self, other: &JsValue) -> bool {
342 match other.as_f64() {
343 Some(n) => *self == n,
344 None => false,
345 }
346 }
347}
348
349macro_rules! impl_partial_eq_int {
351 ($($t:ty),*) => {
352 $(
353 impl PartialEq<$t> for JsValue {
354 fn eq(&self, other: &$t) -> bool {
355 match self.as_f64() {
356 Some(n) => n == (*other as f64),
357 None => false,
358 }
359 }
360 }
361
362 impl PartialEq<JsValue> for $t {
363 fn eq(&self, other: &JsValue) -> bool {
364 match other.as_f64() {
365 Some(n) => (*self as f64) == n,
366 None => false,
367 }
368 }
369 }
370 )*
371 };
372}
373
374impl_partial_eq_int!(
375 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
376);
377
378impl fmt::Debug for JsValue {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 f.write_str(&self.as_debug_string())
381 }
382}
383
384impl PartialEq for JsValue {
385 fn eq(&self, other: &Self) -> bool {
386 self.idx == other.idx
387 }
388}
389
390impl Eq for JsValue {}
391
392impl core::hash::Hash for JsValue {
393 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
394 self.idx.hash(state);
395 }
396}
397
398impl Default for JsValue {
399 fn default() -> Self {
400 Self::UNDEFINED
401 }
402}
403
404impl JsValue {
406 pub fn checked_div(&self, rhs: &Self) -> Self {
408 crate::js_helpers::js_checked_div(self, rhs)
409 }
410
411 pub fn pow(&self, rhs: &Self) -> Self {
413 crate::js_helpers::js_pow(self, rhs)
414 }
415
416 pub fn bit_and(&self, rhs: &JsValue) -> JsValue {
418 crate::js_helpers::js_bit_and(self, rhs)
419 }
420
421 pub fn bit_or(&self, rhs: &JsValue) -> JsValue {
423 crate::js_helpers::js_bit_or(self, rhs)
424 }
425
426 pub fn bit_xor(&self, rhs: &JsValue) -> JsValue {
428 crate::js_helpers::js_bit_xor(self, rhs)
429 }
430
431 pub fn bit_not(&self) -> JsValue {
433 crate::js_helpers::js_bit_not(self)
434 }
435
436 pub fn shl(&self, rhs: &JsValue) -> JsValue {
438 crate::js_helpers::js_shl(self, rhs)
439 }
440
441 pub fn shr(&self, rhs: &JsValue) -> JsValue {
443 crate::js_helpers::js_shr(self, rhs)
444 }
445
446 pub fn unsigned_shr(&self, rhs: &Self) -> u32 {
448 crate::js_helpers::js_unsigned_shr(self, rhs)
449 }
450
451 pub fn add(&self, rhs: &JsValue) -> JsValue {
453 crate::js_helpers::js_add(self, rhs)
454 }
455
456 pub fn sub(&self, rhs: &JsValue) -> JsValue {
458 crate::js_helpers::js_sub(self, rhs)
459 }
460
461 pub fn mul(&self, rhs: &JsValue) -> JsValue {
463 crate::js_helpers::js_mul(self, rhs)
464 }
465
466 pub fn div(&self, rhs: &JsValue) -> JsValue {
468 crate::js_helpers::js_div(self, rhs)
469 }
470
471 pub fn rem(&self, rhs: &JsValue) -> JsValue {
473 crate::js_helpers::js_rem(self, rhs)
474 }
475
476 pub fn neg(&self) -> JsValue {
478 crate::js_helpers::js_neg(self)
479 }
480
481 pub fn lt(&self, other: &Self) -> bool {
483 crate::js_helpers::js_lt(self, other)
484 }
485
486 pub fn le(&self, other: &Self) -> bool {
488 crate::js_helpers::js_le(self, other)
489 }
490
491 pub fn gt(&self, other: &Self) -> bool {
493 crate::js_helpers::js_gt(self, other)
494 }
495
496 pub fn ge(&self, other: &Self) -> bool {
498 crate::js_helpers::js_ge(self, other)
499 }
500
501 pub fn loose_eq(&self, other: &Self) -> bool {
503 crate::js_helpers::js_loose_eq(self, other)
504 }
505
506 pub fn is_falsy(&self) -> bool {
508 crate::js_helpers::js_is_falsy(self)
509 }
510
511 pub fn is_truthy(&self) -> bool {
513 crate::js_helpers::js_is_truthy(self)
514 }
515
516 pub fn is_object(&self) -> bool {
518 crate::js_helpers::js_is_object(self)
519 }
520
521 pub fn is_function(&self) -> bool {
523 crate::js_helpers::js_is_function(self)
524 }
525
526 pub fn is_string(&self) -> bool {
528 crate::js_helpers::js_is_string(self)
529 }
530
531 pub fn is_symbol(&self) -> bool {
533 crate::js_helpers::js_is_symbol(self)
534 }
535
536 pub fn is_bigint(&self) -> bool {
538 crate::js_helpers::js_is_bigint(self)
539 }
540
541 pub fn is_array(&self) -> bool {
543 crate::js_helpers::js_is_array(self)
544 }
545
546 pub fn is_undefined(&self) -> bool {
548 if self.idx == JSIDX_UNDEFINED {
549 return true;
550 }
551 crate::js_helpers::js_is_undefined(self)
552 }
553
554 pub fn is_null(&self) -> bool {
556 if self.idx == JSIDX_NULL {
557 return true;
558 }
559 crate::js_helpers::js_is_null(self)
560 }
561
562 pub fn is_null_or_undefined(&self) -> bool {
564 if self.idx == JSIDX_NULL || self.idx == JSIDX_UNDEFINED {
565 return true;
566 }
567 crate::js_helpers::js_is_null_or_undefined(self)
568 }
569
570 pub fn js_typeof(&self) -> JsValue {
572 crate::js_helpers::js_typeof(self)
573 }
574
575 pub fn js_in(&self, obj: &JsValue) -> bool {
577 crate::js_helpers::js_in(self, obj)
578 }
579
580 pub fn as_bool(&self) -> Option<bool> {
582 match self.idx {
583 JSIDX_TRUE => Some(true),
584 JSIDX_FALSE => Some(false),
585 JSIDX_UNDEFINED | JSIDX_NULL => None,
586 _ => {
587 if crate::js_helpers::js_is_true(self) {
589 Some(true)
590 } else if crate::js_helpers::js_is_false(self) {
591 Some(false)
592 } else {
593 None
594 }
595 }
596 }
597 }
598
599 pub fn as_f64(&self) -> Option<f64> {
601 crate::js_helpers::js_as_f64(self)
602 }
603
604 pub fn as_string(&self) -> Option<String> {
606 crate::js_helpers::js_as_string(self)
607 }
608
609 pub fn as_debug_string(&self) -> String {
611 crate::js_helpers::js_debug_string(self)
612 }
613}
614
615use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub};
617
618impl Neg for &JsValue {
619 type Output = JsValue;
620 fn neg(self) -> Self::Output {
621 JsValue::neg(self)
622 }
623}
624
625impl Not for &JsValue {
626 type Output = bool;
627
628 fn not(self) -> Self::Output {
629 JsValue::is_falsy(self)
630 }
631}
632
633impl BitAnd for &JsValue {
634 type Output = JsValue;
635 fn bitand(self, rhs: Self) -> Self::Output {
636 JsValue::bit_and(self, rhs)
637 }
638}
639
640impl BitOr for &JsValue {
641 type Output = JsValue;
642 fn bitor(self, rhs: Self) -> Self::Output {
643 JsValue::bit_or(self, rhs)
644 }
645}
646
647impl BitXor for &JsValue {
648 type Output = JsValue;
649 fn bitxor(self, rhs: Self) -> Self::Output {
650 JsValue::bit_xor(self, rhs)
651 }
652}
653
654impl Shl for &JsValue {
655 type Output = JsValue;
656 fn shl(self, rhs: Self) -> Self::Output {
657 JsValue::shl(self, rhs)
658 }
659}
660
661impl Shr for &JsValue {
662 type Output = JsValue;
663 fn shr(self, rhs: Self) -> Self::Output {
664 JsValue::shr(self, rhs)
665 }
666}
667
668impl Add for &JsValue {
669 type Output = JsValue;
670 fn add(self, rhs: Self) -> Self::Output {
671 JsValue::add(self, rhs)
672 }
673}
674
675impl Sub for &JsValue {
676 type Output = JsValue;
677 fn sub(self, rhs: Self) -> Self::Output {
678 JsValue::sub(self, rhs)
679 }
680}
681
682impl Mul for &JsValue {
683 type Output = JsValue;
684 fn mul(self, rhs: Self) -> Self::Output {
685 JsValue::mul(self, rhs)
686 }
687}
688
689impl Div for &JsValue {
690 type Output = JsValue;
691 fn div(self, rhs: Self) -> Self::Output {
692 JsValue::div(self, rhs)
693 }
694}
695
696impl Rem for &JsValue {
697 type Output = JsValue;
698 fn rem(self, rhs: Self) -> Self::Output {
699 JsValue::rem(self, rhs)
700 }
701}
702
703impl Neg for JsValue {
704 type Output = JsValue;
705 fn neg(self) -> JsValue {
706 JsValue::neg(&self)
707 }
708}
709
710impl Not for JsValue {
711 type Output = bool;
712 fn not(self) -> Self::Output {
713 JsValue::is_falsy(&self)
714 }
715}
716
717macro_rules! impl_binary_op {
719 ($trait:ident, $method:ident, $js_method:ident) => {
720 impl $trait for JsValue {
722 type Output = JsValue;
723 fn $method(self, rhs: JsValue) -> JsValue {
724 JsValue::$js_method(&self, &rhs)
725 }
726 }
727
728 impl $trait<&JsValue> for JsValue {
730 type Output = JsValue;
731 fn $method(self, rhs: &JsValue) -> JsValue {
732 JsValue::$js_method(&self, rhs)
733 }
734 }
735
736 impl<'a> $trait<JsValue> for &'a JsValue {
738 type Output = JsValue;
739 fn $method(self, rhs: JsValue) -> JsValue {
740 JsValue::$js_method(self, &rhs)
741 }
742 }
743 };
744}
745
746impl_binary_op!(Add, add, add);
747impl_binary_op!(Sub, sub, sub);
748impl_binary_op!(Mul, mul, mul);
749impl_binary_op!(Div, div, div);
750impl_binary_op!(Rem, rem, rem);
751impl_binary_op!(BitAnd, bitand, bit_and);
752impl_binary_op!(BitOr, bitor, bit_or);
753impl_binary_op!(BitXor, bitxor, bit_xor);
754impl_binary_op!(Shl, shl, shl);
755impl_binary_op!(Shr, shr, shr);
756
757impl From<bool> for JsValue {
758 fn from(s: bool) -> JsValue {
759 JsValue::from_bool(s)
760 }
761}
762
763impl<T> From<*mut T> for JsValue {
764 fn from(s: *mut T) -> JsValue {
765 JsValue::from(s as usize)
766 }
767}
768
769impl<T> From<*const T> for JsValue {
770 fn from(s: *const T) -> JsValue {
771 JsValue::from(s as usize)
772 }
773}
774
775impl<T> From<NonNull<T>> for JsValue {
776 fn from(s: NonNull<T>) -> JsValue {
777 JsValue::from(s.as_ptr() as usize)
778 }
779}
780
781impl<T> From<Vec<T>> for JsValue
782where
783 Vec<T>: crate::BinaryEncode + crate::EncodeTypeDef,
784{
785 fn from(vector: Vec<T>) -> Self {
786 crate::__rt::wbg_cast(vector)
787 }
788}
789
790impl<T> From<Box<[T]>> for JsValue
791where
792 Box<[T]>: crate::BinaryEncode + crate::EncodeTypeDef,
793{
794 fn from(vector: Box<[T]>) -> Self {
795 crate::__rt::wbg_cast(vector)
796 }
797}
798
799impl<T> From<crate::Clamped<Vec<T>>> for JsValue
800where
801 crate::Clamped<Vec<T>>: crate::BinaryEncode + crate::EncodeTypeDef,
802{
803 fn from(vector: crate::Clamped<Vec<T>>) -> Self {
804 crate::__rt::wbg_cast(vector)
805 }
806}
807
808impl<T> From<crate::Clamped<Box<[T]>>> for JsValue
809where
810 crate::Clamped<Vec<T>>: crate::BinaryEncode + crate::EncodeTypeDef,
811{
812 fn from(vector: crate::Clamped<Box<[T]>>) -> Self {
813 crate::__rt::wbg_cast(crate::Clamped(vector.0.into_vec()))
814 }
815}