1use crate::__rt::{JsRef, JsRefEncode};
7use alloc::{boxed::Box, string::String, vec::Vec};
8use core::fmt;
9use core::ptr::NonNull;
10use wry_bindgen_core::Clamped;
11
12pub struct JsValue {
24 idx: JsRef,
27}
28
29impl JsValue {
30 pub const NULL: JsValue = JsValue::from_ref(JsRef::NULL);
32
33 pub const UNDEFINED: JsValue = JsValue::from_ref(JsRef::UNDEFINED);
35
36 pub const TRUE: JsValue = JsValue::from_ref(JsRef::TRUE);
38
39 pub const FALSE: JsValue = JsValue::from_ref(JsRef::FALSE);
41
42 #[inline]
46 pub(crate) const fn from_ref(js_ref: JsRef) -> Self {
47 Self { idx: js_ref }
48 }
49
50 #[inline]
54 pub(crate) fn js_ref(&self) -> JsRef {
55 self.idx
56 }
57
58 #[cfg(feature = "serde-serialize")]
70 #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` instead"]
71 pub fn from_serde<T>(t: &T) -> serde_json::Result<JsValue>
72 where
73 T: serde::ser::Serialize + ?Sized,
74 {
75 let json = serde_json::to_string(t)?;
76 Ok(crate::__wry_call_js_function!(
77 "(s) => JSON.parse(s)",
78 fn(&str) -> JsValue,
79 (json.as_str())
80 ))
81 }
82
83 #[cfg(feature = "serde-serialize")]
95 #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` instead"]
96 pub fn into_serde<T>(&self) -> serde_json::Result<T>
97 where
98 T: for<'a> serde::de::Deserialize<'a>,
99 {
100 let json: String = crate::__wry_call_js_function!(
103 "(v) => JSON.stringify(v) ?? \"null\"",
104 fn(JsValue) -> String,
105 (self.clone())
106 );
107 serde_json::from_str(&json)
108 }
109
110 #[inline]
113 pub fn unchecked_into_f64(&self) -> f64 {
114 crate::js_helpers::js_as_number(self)
116 }
117
118 #[inline]
120 pub fn has_type<T: crate::JsCast>(&self) -> bool {
121 T::is_type_of(self)
122 }
123
124 #[inline]
128 pub fn into_abi(self) -> u32 {
129 let id = self.idx.into_abi();
130 core::mem::forget(self);
131 id
132 }
133
134 #[inline]
136 pub const fn undefined() -> JsValue {
137 JsValue::UNDEFINED
138 }
139
140 #[inline]
142 pub const fn null() -> JsValue {
143 JsValue::NULL
144 }
145
146 #[inline]
148 pub const fn from_bool(b: bool) -> JsValue {
149 if b { JsValue::TRUE } else { JsValue::FALSE }
150 }
151
152 #[allow(clippy::should_implement_trait)]
154 pub fn from_str(s: &str) -> JsValue {
155 s.into()
156 }
157
158 pub fn from_f64(n: f64) -> JsValue {
160 n.into()
161 }
162
163 pub fn bigint_from_str(s: &str) -> JsValue {
165 crate::js_helpers::js_bigint_from_str(s)
166 }
167
168 pub fn symbol(description: Option<&str>) -> JsValue {
170 crate::js_helpers::js_symbol_new(description)
171 }
172}
173
174impl Clone for JsValue {
175 #[inline]
176 fn clone(&self) -> JsValue {
177 crate::js_helpers::js_clone_heap_ref(self)
184 }
185}
186
187impl JsRefEncode for JsValue {
188 #[inline]
189 fn js_ref(&self) -> JsRef {
190 self.js_ref()
191 }
192}
193
194impl Drop for JsValue {
195 #[inline]
196 fn drop(&mut self) {
197 if !self.idx.is_owned_heap_ref() {
199 return;
200 }
201
202 self.idx.drop_js_object();
204 }
205}
206
207impl<'a> PartialEq<&'a str> for JsValue {
208 fn eq(&self, other: &&'a str) -> bool {
209 match self.as_string() {
210 Some(s) => &s == other,
211 None => false,
212 }
213 }
214}
215
216impl PartialEq<JsValue> for &str {
217 fn eq(&self, other: &JsValue) -> bool {
218 match other.as_string() {
219 Some(s) => self == &s,
220 None => false,
221 }
222 }
223}
224
225impl PartialEq<str> for JsValue {
226 fn eq(&self, other: &str) -> bool {
227 match self.as_string() {
228 Some(s) => s == other,
229 None => false,
230 }
231 }
232}
233
234impl PartialEq<String> for JsValue {
235 fn eq(&self, other: &String) -> bool {
236 match self.as_string() {
237 Some(s) => &s == other,
238 None => false,
239 }
240 }
241}
242
243impl PartialEq<JsValue> for String {
244 fn eq(&self, other: &JsValue) -> bool {
245 match other.as_string() {
246 Some(s) => self == &s,
247 None => false,
248 }
249 }
250}
251
252impl<'a> PartialEq<&'a String> for JsValue {
253 fn eq(&self, other: &&'a String) -> bool {
254 match self.as_string() {
255 Some(s) => &s == *other,
256 None => false,
257 }
258 }
259}
260
261impl PartialEq<JsValue> for &String {
262 fn eq(&self, other: &JsValue) -> bool {
263 match other.as_string() {
264 Some(s) => *self == &s,
265 None => false,
266 }
267 }
268}
269
270impl PartialEq<bool> for JsValue {
271 fn eq(&self, other: &bool) -> bool {
272 match self.as_bool() {
273 Some(b) => b == *other,
274 None => false,
275 }
276 }
277}
278
279impl PartialEq<JsValue> for bool {
280 fn eq(&self, other: &JsValue) -> bool {
281 match other.as_bool() {
282 Some(b) => *self == b,
283 None => false,
284 }
285 }
286}
287
288impl PartialEq<f32> for JsValue {
289 fn eq(&self, other: &f32) -> bool {
290 match self.as_f64() {
291 Some(n) => n == (*other as f64),
292 None => false,
293 }
294 }
295}
296
297impl PartialEq<JsValue> for f32 {
298 fn eq(&self, other: &JsValue) -> bool {
299 match other.as_f64() {
300 Some(n) => (*self as f64) == n,
301 None => false,
302 }
303 }
304}
305
306impl PartialEq<f64> for JsValue {
307 fn eq(&self, other: &f64) -> bool {
308 match self.as_f64() {
309 Some(n) => n == *other,
310 None => false,
311 }
312 }
313}
314
315impl PartialEq<JsValue> for f64 {
316 fn eq(&self, other: &JsValue) -> bool {
317 match other.as_f64() {
318 Some(n) => *self == n,
319 None => false,
320 }
321 }
322}
323
324macro_rules! impl_partial_eq_int {
326 ($($t:ty),*) => {
327 $(
328 impl PartialEq<$t> for JsValue {
329 fn eq(&self, other: &$t) -> bool {
330 match self.as_f64() {
331 Some(n) => n == (*other as f64),
332 None => false,
333 }
334 }
335 }
336
337 impl PartialEq<JsValue> for $t {
338 fn eq(&self, other: &JsValue) -> bool {
339 match other.as_f64() {
340 Some(n) => (*self as f64) == n,
341 None => false,
342 }
343 }
344 }
345 )*
346 };
347}
348
349impl_partial_eq_int!(i8, i16, i32, isize, u8, u16, u32, usize);
350
351macro_rules! impl_partial_eq_bigint {
354 ($($t:ty),*) => {
355 $(
356 impl PartialEq<$t> for JsValue {
357 fn eq(&self, other: &$t) -> bool {
358 *self == JsValue::from(*other)
359 }
360 }
361
362 impl PartialEq<JsValue> for $t {
363 fn eq(&self, other: &JsValue) -> bool {
364 JsValue::from(*self) == *other
365 }
366 }
367 )*
368 };
369}
370
371impl_partial_eq_bigint!(i64, u64, i128, u128);
372
373impl fmt::Debug for JsValue {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 write!(f, "JsValue({})", self.as_debug_string())
376 }
377}
378
379impl PartialEq for JsValue {
380 fn eq(&self, other: &Self) -> bool {
382 crate::js_helpers::js_strict_eq(self, other)
383 }
384}
385
386impl Eq for JsValue {}
387
388impl core::hash::Hash for JsValue {
389 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
390 core::hash::Hash::hash(&self.idx, state);
391 }
392}
393
394impl Default for JsValue {
395 fn default() -> Self {
396 Self::UNDEFINED
397 }
398}
399
400impl JsValue {
402 pub fn checked_div(&self, rhs: &Self) -> Self {
404 crate::js_helpers::js_checked_div(self, rhs)
405 }
406
407 pub fn pow(&self, rhs: &Self) -> Self {
409 crate::js_helpers::js_pow(self, rhs)
410 }
411
412 pub fn bit_and(&self, rhs: &JsValue) -> JsValue {
414 crate::js_helpers::js_bit_and(self, rhs)
415 }
416
417 pub fn bit_or(&self, rhs: &JsValue) -> JsValue {
419 crate::js_helpers::js_bit_or(self, rhs)
420 }
421
422 pub fn bit_xor(&self, rhs: &JsValue) -> JsValue {
424 crate::js_helpers::js_bit_xor(self, rhs)
425 }
426
427 pub fn bit_not(&self) -> JsValue {
429 crate::js_helpers::js_bit_not(self)
430 }
431
432 pub fn shl(&self, rhs: &JsValue) -> JsValue {
434 crate::js_helpers::js_shl(self, rhs)
435 }
436
437 pub fn shr(&self, rhs: &JsValue) -> JsValue {
439 crate::js_helpers::js_shr(self, rhs)
440 }
441
442 pub fn unsigned_shr(&self, rhs: &Self) -> u32 {
444 crate::js_helpers::js_unsigned_shr(self, rhs)
445 }
446
447 pub fn add(&self, rhs: &JsValue) -> JsValue {
449 crate::js_helpers::js_add(self, rhs)
450 }
451
452 pub fn sub(&self, rhs: &JsValue) -> JsValue {
454 crate::js_helpers::js_sub(self, rhs)
455 }
456
457 pub fn mul(&self, rhs: &JsValue) -> JsValue {
459 crate::js_helpers::js_mul(self, rhs)
460 }
461
462 pub fn div(&self, rhs: &JsValue) -> JsValue {
464 crate::js_helpers::js_div(self, rhs)
465 }
466
467 pub fn rem(&self, rhs: &JsValue) -> JsValue {
469 crate::js_helpers::js_rem(self, rhs)
470 }
471
472 pub fn neg(&self) -> JsValue {
474 crate::js_helpers::js_neg(self)
475 }
476
477 pub fn lt(&self, other: &Self) -> bool {
479 crate::js_helpers::js_lt(self, other)
480 }
481
482 pub fn le(&self, other: &Self) -> bool {
484 crate::js_helpers::js_le(self, other)
485 }
486
487 pub fn gt(&self, other: &Self) -> bool {
489 crate::js_helpers::js_gt(self, other)
490 }
491
492 pub fn ge(&self, other: &Self) -> bool {
494 crate::js_helpers::js_ge(self, other)
495 }
496
497 pub fn loose_eq(&self, other: &Self) -> bool {
499 crate::js_helpers::js_loose_eq(self, other)
500 }
501
502 pub fn is_falsy(&self) -> bool {
504 crate::js_helpers::js_is_falsy(self)
505 }
506
507 pub fn is_truthy(&self) -> bool {
509 crate::js_helpers::js_is_truthy(self)
510 }
511
512 pub fn is_object(&self) -> bool {
514 crate::js_helpers::js_is_object(self)
515 }
516
517 pub fn is_function(&self) -> bool {
519 crate::js_helpers::js_is_function(self)
520 }
521
522 pub fn is_string(&self) -> bool {
524 crate::js_helpers::js_is_string(self)
525 }
526
527 pub fn is_symbol(&self) -> bool {
529 crate::js_helpers::js_is_symbol(self)
530 }
531
532 pub fn is_bigint(&self) -> bool {
534 crate::js_helpers::js_is_bigint(self)
535 }
536
537 pub fn is_array(&self) -> bool {
539 crate::js_helpers::js_is_array(self)
540 }
541
542 pub fn is_undefined(&self) -> bool {
544 if self.idx == JsRef::UNDEFINED {
545 return true;
546 }
547 crate::js_helpers::js_is_undefined(self)
548 }
549
550 pub fn is_null(&self) -> bool {
552 if self.idx == JsRef::NULL {
553 return true;
554 }
555 crate::js_helpers::js_is_null(self)
556 }
557
558 pub fn is_null_or_undefined(&self) -> bool {
560 if self.idx == JsRef::NULL || self.idx == JsRef::UNDEFINED {
561 return true;
562 }
563 crate::js_helpers::js_is_null_or_undefined(self)
564 }
565
566 pub fn js_typeof(&self) -> JsValue {
568 crate::js_helpers::js_typeof(self)
569 }
570
571 pub fn js_in(&self, obj: &JsValue) -> bool {
573 crate::js_helpers::js_in(self, obj)
574 }
575
576 pub fn as_bool(&self) -> Option<bool> {
578 if self.idx == JsRef::TRUE {
579 Some(true)
580 } else if self.idx == JsRef::FALSE {
581 Some(false)
582 } else if self.idx == JsRef::UNDEFINED || self.idx == JsRef::NULL {
583 None
584 } else if crate::js_helpers::js_is_true(self) {
585 Some(true)
586 } else if crate::js_helpers::js_is_false(self) {
587 Some(false)
588 } else {
589 None
590 }
591 }
592
593 pub fn as_f64(&self) -> Option<f64> {
595 crate::js_helpers::js_as_f64(self)
596 }
597
598 pub fn as_string(&self) -> Option<String> {
600 crate::js_helpers::js_as_string(self)
601 }
602
603 pub fn as_debug_string(&self) -> String {
605 crate::js_helpers::js_debug_string(self)
606 }
607}
608
609use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub};
611
612impl Neg for &JsValue {
613 type Output = JsValue;
614 fn neg(self) -> Self::Output {
615 JsValue::neg(self)
616 }
617}
618
619impl Not for &JsValue {
620 type Output = bool;
621
622 fn not(self) -> Self::Output {
623 JsValue::is_falsy(self)
624 }
625}
626
627impl BitAnd for &JsValue {
628 type Output = JsValue;
629 fn bitand(self, rhs: Self) -> Self::Output {
630 JsValue::bit_and(self, rhs)
631 }
632}
633
634impl BitOr for &JsValue {
635 type Output = JsValue;
636 fn bitor(self, rhs: Self) -> Self::Output {
637 JsValue::bit_or(self, rhs)
638 }
639}
640
641impl BitXor for &JsValue {
642 type Output = JsValue;
643 fn bitxor(self, rhs: Self) -> Self::Output {
644 JsValue::bit_xor(self, rhs)
645 }
646}
647
648impl Shl for &JsValue {
649 type Output = JsValue;
650 fn shl(self, rhs: Self) -> Self::Output {
651 JsValue::shl(self, rhs)
652 }
653}
654
655impl Shr for &JsValue {
656 type Output = JsValue;
657 fn shr(self, rhs: Self) -> Self::Output {
658 JsValue::shr(self, rhs)
659 }
660}
661
662impl Add for &JsValue {
663 type Output = JsValue;
664 fn add(self, rhs: Self) -> Self::Output {
665 JsValue::add(self, rhs)
666 }
667}
668
669impl Sub for &JsValue {
670 type Output = JsValue;
671 fn sub(self, rhs: Self) -> Self::Output {
672 JsValue::sub(self, rhs)
673 }
674}
675
676impl Mul for &JsValue {
677 type Output = JsValue;
678 fn mul(self, rhs: Self) -> Self::Output {
679 JsValue::mul(self, rhs)
680 }
681}
682
683impl Div for &JsValue {
684 type Output = JsValue;
685 fn div(self, rhs: Self) -> Self::Output {
686 JsValue::div(self, rhs)
687 }
688}
689
690impl Rem for &JsValue {
691 type Output = JsValue;
692 fn rem(self, rhs: Self) -> Self::Output {
693 JsValue::rem(self, rhs)
694 }
695}
696
697impl Neg for JsValue {
698 type Output = JsValue;
699 fn neg(self) -> JsValue {
700 JsValue::neg(&self)
701 }
702}
703
704impl Not for JsValue {
705 type Output = bool;
706 fn not(self) -> Self::Output {
707 JsValue::is_falsy(&self)
708 }
709}
710
711macro_rules! impl_binary_op {
713 ($trait:ident, $method:ident, $js_method:ident) => {
714 impl $trait for JsValue {
716 type Output = JsValue;
717 fn $method(self, rhs: JsValue) -> JsValue {
718 JsValue::$js_method(&self, &rhs)
719 }
720 }
721
722 impl $trait<&JsValue> for JsValue {
724 type Output = JsValue;
725 fn $method(self, rhs: &JsValue) -> JsValue {
726 JsValue::$js_method(&self, rhs)
727 }
728 }
729
730 impl<'a> $trait<JsValue> for &'a JsValue {
732 type Output = JsValue;
733 fn $method(self, rhs: JsValue) -> JsValue {
734 JsValue::$js_method(self, &rhs)
735 }
736 }
737 };
738}
739
740impl_binary_op!(Add, add, add);
741impl_binary_op!(Sub, sub, sub);
742impl_binary_op!(Mul, mul, mul);
743impl_binary_op!(Div, div, div);
744impl_binary_op!(Rem, rem, rem);
745impl_binary_op!(BitAnd, bitand, bit_and);
746impl_binary_op!(BitOr, bitor, bit_or);
747impl_binary_op!(BitXor, bitxor, bit_xor);
748impl_binary_op!(Shl, shl, shl);
749impl_binary_op!(Shr, shr, shr);
750
751impl From<bool> for JsValue {
752 fn from(s: bool) -> JsValue {
753 JsValue::from_bool(s)
754 }
755}
756
757impl<T> From<*mut T> for JsValue {
758 fn from(s: *mut T) -> JsValue {
759 JsValue::from(s as usize)
760 }
761}
762
763impl<T> From<*const T> for JsValue {
764 fn from(s: *const T) -> JsValue {
765 JsValue::from(s as usize)
766 }
767}
768
769impl<T> From<NonNull<T>> for JsValue {
770 fn from(s: NonNull<T>) -> JsValue {
771 JsValue::from(s.as_ptr() as usize)
772 }
773}
774
775impl<T> From<Vec<T>> for JsValue
776where
777 Vec<T>: crate::__rt::BinaryEncode + crate::__rt::EncodeTypeDef,
778{
779 fn from(vector: Vec<T>) -> Self {
780 crate::__rt::wbg_cast(vector)
781 }
782}
783
784impl<T> From<Box<[T]>> for JsValue
785where
786 Box<[T]>: crate::__rt::BinaryEncode + crate::__rt::EncodeTypeDef,
787{
788 fn from(vector: Box<[T]>) -> Self {
789 crate::__rt::wbg_cast(vector)
790 }
791}
792
793impl<T> From<Clamped<Vec<T>>> for JsValue
794where
795 Clamped<Vec<T>>: crate::__rt::BinaryEncode + crate::__rt::EncodeTypeDef,
796{
797 fn from(vector: Clamped<Vec<T>>) -> Self {
798 crate::__rt::wbg_cast(vector)
799 }
800}
801
802impl<T> From<Clamped<Box<[T]>>> for JsValue
803where
804 Clamped<Vec<T>>: crate::__rt::BinaryEncode + crate::__rt::EncodeTypeDef,
805{
806 fn from(vector: Clamped<Box<[T]>>) -> Self {
807 crate::__rt::wbg_cast(Clamped(vector.0.into_vec()))
808 }
809}