1use std::{
6 collections::HashSet,
7 fmt::{self, Display},
8 ops::Sub,
9};
10
11use num_bigint::BigInt;
12use num_integer::Integer;
13use num_traits::{ToPrimitive, Zero};
14use once_cell::sync::Lazy;
15
16use boa_gc::{custom_trace, Finalize, Trace};
17#[doc(inline)]
18pub use boa_macros::TryFromJs;
19pub use boa_macros::TryIntoJs;
20use boa_profiler::Profiler;
21#[doc(inline)]
22pub use conversions::convert::Convert;
23
24pub(crate) use self::conversions::IntoOrUndefined;
25#[doc(inline)]
26pub use self::{
27 conversions::try_from_js::TryFromJs, conversions::try_into_js::TryIntoJs,
28 display::ValueDisplay, integer::IntegerOrInfinity, operations::*, r#type::Type,
29};
30use crate::builtins::RegExp;
31use crate::object::{JsFunction, JsPromise, JsRegExp};
32use crate::{
33 builtins::{
34 number::{f64_to_int32, f64_to_uint32},
35 Number, Promise,
36 },
37 error::JsNativeError,
38 js_string,
39 object::JsObject,
40 property::{PropertyDescriptor, PropertyKey},
41 symbol::JsSymbol,
42 Context, JsBigInt, JsResult, JsString,
43};
44
45mod conversions;
46pub(crate) mod display;
47mod equality;
48mod hash;
49mod integer;
50mod operations;
51mod r#type;
52
53#[cfg(test)]
54mod tests;
55
56static TWO_E_64: Lazy<BigInt> = Lazy::new(|| {
57 const TWO_E_64: u128 = 2u128.pow(64);
58 BigInt::from(TWO_E_64)
59});
60
61static TWO_E_63: Lazy<BigInt> = Lazy::new(|| {
62 const TWO_E_63: u128 = 2u128.pow(63);
63 BigInt::from(TWO_E_63)
64});
65
66#[derive(Finalize, Debug, Clone)]
68pub enum JsValue {
69 Null,
71 Undefined,
73 Boolean(bool),
75 String(JsString),
77 Rational(f64),
79 Integer(i32),
81 BigInt(JsBigInt),
83 Object(JsObject),
85 Symbol(JsSymbol),
87}
88
89unsafe impl Trace for JsValue {
90 custom_trace! {this, mark, {
91 if let Self::Object(o) = this {
92 mark(o);
93 }
94 }}
95}
96
97impl JsValue {
98 pub fn new<T>(value: T) -> Self
100 where
101 T: Into<Self>,
102 {
103 value.into()
104 }
105
106 #[inline]
108 #[must_use]
109 pub const fn undefined() -> Self {
110 Self::Undefined
111 }
112
113 #[inline]
115 #[must_use]
116 pub const fn null() -> Self {
117 Self::Null
118 }
119
120 #[inline]
122 #[must_use]
123 pub const fn nan() -> Self {
124 Self::Rational(f64::NAN)
125 }
126
127 #[inline]
129 #[must_use]
130 pub const fn positive_infinity() -> Self {
131 Self::Rational(f64::INFINITY)
132 }
133
134 #[inline]
136 #[must_use]
137 pub const fn negative_infinity() -> Self {
138 Self::Rational(f64::NEG_INFINITY)
139 }
140
141 #[inline]
143 #[must_use]
144 pub const fn is_object(&self) -> bool {
145 matches!(self, Self::Object(_))
146 }
147
148 #[inline]
150 #[must_use]
151 pub const fn as_object(&self) -> Option<&JsObject> {
152 match *self {
153 Self::Object(ref o) => Some(o),
154 _ => None,
155 }
156 }
157
158 #[inline]
165 #[must_use]
166 pub fn is_callable(&self) -> bool {
167 matches!(self, Self::Object(obj) if obj.is_callable())
168 }
169
170 #[inline]
172 #[must_use]
173 pub fn as_callable(&self) -> Option<&JsObject> {
174 self.as_object().filter(|obj| obj.is_callable())
175 }
176
177 #[inline]
180 #[must_use]
181 pub fn as_function(&self) -> Option<JsFunction> {
182 self.as_callable()
183 .cloned()
184 .and_then(JsFunction::from_object)
185 }
186
187 #[inline]
189 #[must_use]
190 pub fn is_constructor(&self) -> bool {
191 matches!(self, Self::Object(obj) if obj.is_constructor())
192 }
193
194 #[inline]
196 #[must_use]
197 pub fn as_constructor(&self) -> Option<&JsObject> {
198 self.as_object().filter(|obj| obj.is_constructor())
199 }
200
201 #[inline]
203 #[must_use]
204 pub fn is_promise(&self) -> bool {
205 matches!(self, Self::Object(obj) if obj.is::<Promise>())
206 }
207
208 #[inline]
210 #[must_use]
211 pub(crate) fn as_promise_object(&self) -> Option<&JsObject> {
212 self.as_object().filter(|obj| obj.is::<Promise>())
213 }
214
215 #[inline]
217 #[must_use]
218 pub fn as_promise(&self) -> Option<JsPromise> {
219 self.as_promise_object()
220 .cloned()
221 .and_then(|o| JsPromise::from_object(o).ok())
222 }
223
224 #[inline]
226 #[must_use]
227 pub fn is_regexp(&self) -> bool {
228 matches!(self, Self::Object(obj) if obj.is::<RegExp>())
229 }
230
231 #[inline]
233 #[must_use]
234 pub fn as_regexp(&self) -> Option<JsRegExp> {
235 self.as_object()
236 .filter(|obj| obj.is::<RegExp>())
237 .cloned()
238 .and_then(|o| JsRegExp::from_object(o).ok())
239 }
240
241 #[inline]
243 #[must_use]
244 pub const fn is_symbol(&self) -> bool {
245 matches!(self, Self::Symbol(_))
246 }
247
248 #[inline]
250 #[must_use]
251 pub fn as_symbol(&self) -> Option<JsSymbol> {
252 match self {
253 Self::Symbol(symbol) => Some(symbol.clone()),
254 _ => None,
255 }
256 }
257
258 #[inline]
260 #[must_use]
261 pub const fn is_undefined(&self) -> bool {
262 matches!(self, Self::Undefined)
263 }
264
265 #[inline]
267 #[must_use]
268 pub const fn is_null(&self) -> bool {
269 matches!(self, Self::Null)
270 }
271
272 #[inline]
274 #[must_use]
275 pub const fn is_null_or_undefined(&self) -> bool {
276 matches!(self, Self::Null | Self::Undefined)
277 }
278
279 #[inline]
281 #[must_use]
282 pub const fn is_double(&self) -> bool {
283 matches!(self, Self::Rational(_))
284 }
285
286 #[must_use]
293 #[allow(clippy::float_cmp)]
294 pub fn is_integral_number(&self) -> bool {
295 let is_rational_integer = |n: f64| n == f64::from(n as i32);
298
299 match *self {
300 Self::Integer(_) => true,
301 Self::Rational(n) if is_rational_integer(n) => true,
302 _ => false,
303 }
304 }
305
306 #[must_use]
310 #[allow(clippy::float_cmp)]
311 pub fn is_integer(&self) -> bool {
312 let is_rational_integer = |n: f64| n.to_bits() == f64::from(n as i32).to_bits();
315
316 match *self {
317 Self::Integer(_) => true,
318 Self::Rational(n) if is_rational_integer(n) => true,
319 _ => false,
320 }
321 }
322
323 #[inline]
325 #[must_use]
326 pub const fn is_number(&self) -> bool {
327 matches!(self, Self::Rational(_) | Self::Integer(_))
328 }
329
330 #[inline]
332 #[must_use]
333 pub fn as_number(&self) -> Option<f64> {
334 match *self {
335 Self::Integer(integer) => Some(integer.into()),
336 Self::Rational(rational) => Some(rational),
337 _ => None,
338 }
339 }
340
341 #[inline]
343 #[must_use]
344 pub const fn is_string(&self) -> bool {
345 matches!(self, Self::String(_))
346 }
347
348 #[inline]
350 #[must_use]
351 pub const fn as_string(&self) -> Option<&JsString> {
352 match self {
353 Self::String(ref string) => Some(string),
354 _ => None,
355 }
356 }
357
358 #[inline]
360 #[must_use]
361 pub const fn is_boolean(&self) -> bool {
362 matches!(self, Self::Boolean(_))
363 }
364
365 #[inline]
367 #[must_use]
368 pub const fn as_boolean(&self) -> Option<bool> {
369 match self {
370 Self::Boolean(boolean) => Some(*boolean),
371 _ => None,
372 }
373 }
374
375 #[inline]
377 #[must_use]
378 pub const fn is_bigint(&self) -> bool {
379 matches!(self, Self::BigInt(_))
380 }
381
382 #[inline]
384 #[must_use]
385 pub const fn as_bigint(&self) -> Option<&JsBigInt> {
386 match self {
387 Self::BigInt(bigint) => Some(bigint),
388 _ => None,
389 }
390 }
391
392 #[must_use]
399 pub fn to_boolean(&self) -> bool {
400 match *self {
401 Self::Symbol(_) | Self::Object(_) => true,
402 Self::String(ref s) if !s.is_empty() => true,
403 Self::Rational(n) if n != 0.0 && !n.is_nan() => true,
404 Self::Integer(n) if n != 0 => true,
405 Self::BigInt(ref n) if !n.is_zero() => true,
406 Self::Boolean(v) => v,
407 _ => false,
408 }
409 }
410
411 pub fn to_primitive(
416 &self,
417 context: &mut Context,
418 preferred_type: PreferredType,
419 ) -> JsResult<Self> {
420 if let Some(input) = self.as_object() {
423 let exotic_to_prim = input.get_method(JsSymbol::to_primitive(), context)?;
425
426 if let Some(exotic_to_prim) = exotic_to_prim {
428 let hint = match preferred_type {
434 PreferredType::Default => js_string!("default"),
435 PreferredType::String => js_string!("string"),
436 PreferredType::Number => js_string!("number"),
437 }
438 .into();
439
440 let result = exotic_to_prim.call(self, &[hint], context)?;
442 return if result.is_object() {
445 Err(JsNativeError::typ()
446 .with_message("Symbol.toPrimitive cannot return an object")
447 .into())
448 } else {
449 Ok(result)
450 };
451 }
452
453 let preferred_type = match preferred_type {
455 PreferredType::Default | PreferredType::Number => PreferredType::Number,
456 PreferredType::String => PreferredType::String,
457 };
458
459 return input.ordinary_to_primitive(context, preferred_type);
461 }
462
463 Ok(self.clone())
465 }
466
467 pub fn to_bigint(&self, context: &mut Context) -> JsResult<JsBigInt> {
474 match self {
475 Self::Null => Err(JsNativeError::typ()
476 .with_message("cannot convert null to a BigInt")
477 .into()),
478 Self::Undefined => Err(JsNativeError::typ()
479 .with_message("cannot convert undefined to a BigInt")
480 .into()),
481 Self::String(ref string) => JsBigInt::from_js_string(string).map_or_else(
482 || {
483 Err(JsNativeError::syntax()
484 .with_message(format!(
485 "cannot convert string '{}' to bigint primitive",
486 string.to_std_string_escaped()
487 ))
488 .into())
489 },
490 Ok,
491 ),
492 Self::Boolean(true) => Ok(JsBigInt::one()),
493 Self::Boolean(false) => Ok(JsBigInt::zero()),
494 Self::Integer(_) | Self::Rational(_) => Err(JsNativeError::typ()
495 .with_message("cannot convert Number to a BigInt")
496 .into()),
497 Self::BigInt(b) => Ok(b.clone()),
498 Self::Object(_) => {
499 let primitive = self.to_primitive(context, PreferredType::Number)?;
500 primitive.to_bigint(context)
501 }
502 Self::Symbol(_) => Err(JsNativeError::typ()
503 .with_message("cannot convert Symbol to a BigInt")
504 .into()),
505 }
506 }
507
508 #[must_use]
523 #[inline]
524 pub const fn display(&self) -> ValueDisplay<'_> {
525 ValueDisplay {
526 value: self,
527 internals: false,
528 }
529 }
530
531 pub fn to_string(&self, context: &mut Context) -> JsResult<JsString> {
535 match self {
536 Self::Null => Ok(js_string!("null")),
537 Self::Undefined => Ok(js_string!("undefined")),
538 Self::Boolean(boolean) => Ok(if *boolean {
539 js_string!("true")
540 } else {
541 js_string!("false")
542 }),
543 Self::Rational(rational) => Ok(Number::to_js_string(*rational)),
544 Self::Integer(integer) => Ok(integer.to_string().into()),
545 Self::String(string) => Ok(string.clone()),
546 Self::Symbol(_) => Err(JsNativeError::typ()
547 .with_message("can't convert symbol to string")
548 .into()),
549 Self::BigInt(ref bigint) => Ok(bigint.to_string().into()),
550 Self::Object(_) => {
551 let primitive = self.to_primitive(context, PreferredType::String)?;
552 primitive.to_string(context)
553 }
554 }
555 }
556
557 pub fn to_object(&self, context: &mut Context) -> JsResult<JsObject> {
563 match self {
564 Self::Undefined | Self::Null => Err(JsNativeError::typ()
565 .with_message("cannot convert 'null' or 'undefined' to object")
566 .into()),
567 Self::Boolean(boolean) => Ok(context
568 .intrinsics()
569 .templates()
570 .boolean()
571 .create(*boolean, Vec::default())),
572 Self::Integer(integer) => Ok(context
573 .intrinsics()
574 .templates()
575 .number()
576 .create(f64::from(*integer), Vec::default())),
577 Self::Rational(rational) => Ok(context
578 .intrinsics()
579 .templates()
580 .number()
581 .create(*rational, Vec::default())),
582 Self::String(ref string) => Ok(context
583 .intrinsics()
584 .templates()
585 .string()
586 .create(string.clone(), vec![string.len().into()])),
587 Self::Symbol(ref symbol) => Ok(context
588 .intrinsics()
589 .templates()
590 .symbol()
591 .create(symbol.clone(), Vec::default())),
592 Self::BigInt(ref bigint) => Ok(context
593 .intrinsics()
594 .templates()
595 .bigint()
596 .create(bigint.clone(), Vec::default())),
597 Self::Object(jsobject) => Ok(jsobject.clone()),
598 }
599 }
600
601 pub fn to_property_key(&self, context: &mut Context) -> JsResult<PropertyKey> {
605 Ok(match self {
606 Self::String(string) => string.clone().into(),
608 Self::Symbol(symbol) => symbol.clone().into(),
609 Self::Integer(integer) => (*integer).into(),
610 Self::Object(_) => match self.to_primitive(context, PreferredType::String)? {
612 Self::String(ref string) => string.clone().into(),
613 Self::Symbol(ref symbol) => symbol.clone().into(),
614 Self::Integer(integer) => integer.into(),
615 primitive => primitive.to_string(context)?.into(),
616 },
617 primitive => primitive.to_string(context)?.into(),
618 })
619 }
620
621 pub fn to_numeric(&self, context: &mut Context) -> JsResult<Numeric> {
625 let primitive = self.to_primitive(context, PreferredType::Number)?;
627
628 if let Some(bigint) = primitive.as_bigint() {
630 return Ok(bigint.clone().into());
631 }
632
633 Ok(primitive.to_number(context)?.into())
635 }
636
637 pub fn to_u32(&self, context: &mut Context) -> JsResult<u32> {
643 if let Self::Integer(number) = *self {
645 if let Ok(number) = u32::try_from(number) {
646 return Ok(number);
647 }
648 }
649 let number = self.to_number(context)?;
650
651 Ok(f64_to_uint32(number))
652 }
653
654 pub fn to_i32(&self, context: &mut Context) -> JsResult<i32> {
658 if let Self::Integer(number) = *self {
660 return Ok(number);
661 }
662 let number = self.to_number(context)?;
663
664 Ok(f64_to_int32(number))
665 }
666
667 pub fn to_int8(&self, context: &mut Context) -> JsResult<i8> {
674 let number = self.to_number(context)?;
676
677 if number.is_nan() || number.is_zero() || number.is_infinite() {
679 return Ok(0);
680 }
681
682 let int = number.abs().floor().copysign(number) as i64;
684
685 let int_8_bit = int % 2i64.pow(8);
687
688 if int_8_bit >= 2i64.pow(7) {
690 Ok((int_8_bit - 2i64.pow(8)) as i8)
691 } else {
692 Ok(int_8_bit as i8)
693 }
694 }
695
696 pub fn to_uint8(&self, context: &mut Context) -> JsResult<u8> {
703 let number = self.to_number(context)?;
705
706 if number.is_nan() || number.is_zero() || number.is_infinite() {
708 return Ok(0);
709 }
710
711 let int = number.abs().floor().copysign(number) as i64;
713
714 let int_8_bit = int % 2i64.pow(8);
716
717 Ok(int_8_bit as u8)
719 }
720
721 pub fn to_uint8_clamp(&self, context: &mut Context) -> JsResult<u8> {
728 let number = self.to_number(context)?;
730
731 if number.is_nan() {
733 return Ok(0);
734 }
735
736 if number <= 0.0 {
738 return Ok(0);
739 }
740
741 if number >= 255.0 {
743 return Ok(255);
744 }
745
746 let f = number.floor();
748
749 if f + 0.5 < number {
751 return Ok(f as u8 + 1);
752 }
753
754 if number < f + 0.5 {
756 return Ok(f as u8);
757 }
758
759 if f as u8 % 2 != 0 {
761 return Ok(f as u8 + 1);
762 }
763
764 Ok(f as u8)
766 }
767
768 pub fn to_int16(&self, context: &mut Context) -> JsResult<i16> {
775 let number = self.to_number(context)?;
777
778 if number.is_nan() || number.is_zero() || number.is_infinite() {
780 return Ok(0);
781 }
782
783 let int = number.abs().floor().copysign(number) as i64;
785
786 let int_16_bit = int % 2i64.pow(16);
788
789 if int_16_bit >= 2i64.pow(15) {
791 Ok((int_16_bit - 2i64.pow(16)) as i16)
792 } else {
793 Ok(int_16_bit as i16)
794 }
795 }
796
797 pub fn to_uint16(&self, context: &mut Context) -> JsResult<u16> {
804 let number = self.to_number(context)?;
806
807 if number.is_nan() || number.is_zero() || number.is_infinite() {
809 return Ok(0);
810 }
811
812 let int = number.abs().floor().copysign(number) as i64;
814
815 let int_16_bit = int % 2i64.pow(16);
817
818 Ok(int_16_bit as u16)
820 }
821
822 pub fn to_big_int64(&self, context: &mut Context) -> JsResult<i64> {
829 let n = self.to_bigint(context)?;
831
832 let int64_bit = n.as_inner().mod_floor(&TWO_E_64);
834
835 let value = if int64_bit >= *TWO_E_63 {
837 int64_bit.sub(&*TWO_E_64)
838 } else {
839 int64_bit
840 };
841
842 Ok(value
843 .to_i64()
844 .expect("should be within the range of `i64` by the mod operation"))
845 }
846
847 pub fn to_big_uint64(&self, context: &mut Context) -> JsResult<u64> {
854 let n = self.to_bigint(context)?;
856
857 Ok(n.as_inner()
860 .mod_floor(&TWO_E_64)
861 .to_u64()
862 .expect("should be within the range of `u64` by the mod operation"))
863 }
864
865 pub fn to_index(&self, context: &mut Context) -> JsResult<u64> {
869 if self.is_undefined() {
871 return Ok(0);
873 }
874
875 let integer = self.to_integer_or_infinity(context)?;
878
879 let clamped = integer.clamp_finite(0, Number::MAX_SAFE_INTEGER as i64);
881
882 if integer != clamped {
884 return Err(JsNativeError::range()
885 .with_message("Index must be between 0 and 2^53 - 1")
886 .into());
887 }
888
889 debug_assert!(0 <= clamped && clamped <= Number::MAX_SAFE_INTEGER as i64);
891
892 Ok(clamped as u64)
894 }
895
896 pub fn to_length(&self, context: &mut Context) -> JsResult<u64> {
900 Ok(self
904 .to_integer_or_infinity(context)?
905 .clamp_finite(0, Number::MAX_SAFE_INTEGER as i64) as u64)
906 }
907
908 pub fn to_integer_or_infinity(&self, context: &mut Context) -> JsResult<IntegerOrInfinity> {
918 let number = self.to_number(context)?;
920
921 Ok(IntegerOrInfinity::from(number))
923 }
924
925 pub fn to_number(&self, context: &mut Context) -> JsResult<f64> {
931 match *self {
932 Self::Null => Ok(0.0),
933 Self::Undefined => Ok(f64::NAN),
934 Self::Boolean(b) => Ok(if b { 1.0 } else { 0.0 }),
935 Self::String(ref string) => Ok(string.to_number()),
936 Self::Rational(number) => Ok(number),
937 Self::Integer(integer) => Ok(f64::from(integer)),
938 Self::Symbol(_) => Err(JsNativeError::typ()
939 .with_message("argument must not be a symbol")
940 .into()),
941 Self::BigInt(_) => Err(JsNativeError::typ()
942 .with_message("argument must not be a bigint")
943 .into()),
944 Self::Object(_) => {
945 let primitive = self.to_primitive(context, PreferredType::Number)?;
946 primitive.to_number(context)
947 }
948 }
949 }
950
951 pub fn to_f32(&self, context: &mut Context) -> JsResult<f32> {
953 self.to_number(context).map(|n| n as f32)
954 }
955
956 pub fn to_numeric_number(&self, context: &mut Context) -> JsResult<f64> {
962 let primitive = self.to_primitive(context, PreferredType::Number)?;
963 if let Some(bigint) = primitive.as_bigint() {
964 return Ok(bigint.to_f64());
965 }
966 primitive.to_number(context)
967 }
968
969 #[inline]
981 pub fn require_object_coercible(&self) -> JsResult<&Self> {
982 if self.is_null_or_undefined() {
983 Err(JsNativeError::typ()
984 .with_message("cannot convert null or undefined to Object")
985 .into())
986 } else {
987 Ok(self)
988 }
989 }
990
991 #[inline]
998 pub fn to_property_descriptor(&self, context: &mut Context) -> JsResult<PropertyDescriptor> {
999 self.as_object()
1001 .ok_or_else(|| {
1002 JsNativeError::typ()
1003 .with_message("Cannot construct a property descriptor from a non-object")
1004 .into()
1005 })
1006 .and_then(|obj| obj.to_property_descriptor(context))
1007 }
1008
1009 #[must_use]
1017 pub fn type_of(&self) -> &'static str {
1018 match *self {
1019 Self::Rational(_) | Self::Integer(_) => "number",
1020 Self::String(_) => "string",
1021 Self::Boolean(_) => "boolean",
1022 Self::Symbol(_) => "symbol",
1023 Self::Null => "object",
1024 Self::Undefined => "undefined",
1025 Self::BigInt(_) => "bigint",
1026 Self::Object(ref object) => {
1027 if object.is_callable() {
1028 "function"
1029 } else {
1030 "object"
1031 }
1032 }
1033 }
1034 }
1035
1036 #[must_use]
1038 pub fn js_type_of(&self) -> JsString {
1039 match *self {
1040 Self::Rational(_) | Self::Integer(_) => js_string!("number"),
1041 Self::String(_) => js_string!("string"),
1042 Self::Boolean(_) => js_string!("boolean"),
1043 Self::Symbol(_) => js_string!("symbol"),
1044 Self::Null => js_string!("object"),
1045 Self::Undefined => js_string!("undefined"),
1046 Self::BigInt(_) => js_string!("bigint"),
1047 Self::Object(ref object) => {
1048 if object.is_callable() {
1049 js_string!("function")
1050 } else {
1051 js_string!("object")
1052 }
1053 }
1054 }
1055 }
1056
1057 #[inline]
1080 #[must_use]
1081 pub fn map<T, F>(&self, f: F) -> Option<T>
1082 where
1083 F: FnOnce(&JsValue) -> T,
1084 {
1085 if self.is_undefined() {
1086 return None;
1087 }
1088 Some(f(self))
1089 }
1090
1091 pub(crate) fn is_array(&self) -> JsResult<bool> {
1100 self.as_object()
1105 .map_or(Ok(false), JsObject::is_array_abstract)
1106 }
1107}
1108
1109impl Default for JsValue {
1110 fn default() -> Self {
1111 Self::Undefined
1112 }
1113}
1114
1115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1117pub enum PreferredType {
1118 String,
1120
1121 Number,
1123
1124 Default,
1126}
1127
1128#[derive(Debug, Clone, PartialEq, PartialOrd)]
1130pub enum Numeric {
1131 Number(f64),
1133 BigInt(JsBigInt),
1135}
1136
1137impl From<f64> for Numeric {
1138 #[inline]
1139 fn from(value: f64) -> Self {
1140 Self::Number(value)
1141 }
1142}
1143
1144impl From<f32> for Numeric {
1145 #[inline]
1146 fn from(value: f32) -> Self {
1147 Self::Number(value.into())
1148 }
1149}
1150
1151impl From<i64> for Numeric {
1152 #[inline]
1153 fn from(value: i64) -> Self {
1154 Self::BigInt(value.into())
1155 }
1156}
1157
1158impl From<i32> for Numeric {
1159 #[inline]
1160 fn from(value: i32) -> Self {
1161 Self::Number(value.into())
1162 }
1163}
1164
1165impl From<i16> for Numeric {
1166 #[inline]
1167 fn from(value: i16) -> Self {
1168 Self::Number(value.into())
1169 }
1170}
1171
1172impl From<i8> for Numeric {
1173 #[inline]
1174 fn from(value: i8) -> Self {
1175 Self::Number(value.into())
1176 }
1177}
1178
1179impl From<u64> for Numeric {
1180 #[inline]
1181 fn from(value: u64) -> Self {
1182 Self::BigInt(value.into())
1183 }
1184}
1185
1186impl From<u32> for Numeric {
1187 #[inline]
1188 fn from(value: u32) -> Self {
1189 Self::Number(value.into())
1190 }
1191}
1192
1193impl From<u16> for Numeric {
1194 #[inline]
1195 fn from(value: u16) -> Self {
1196 Self::Number(value.into())
1197 }
1198}
1199
1200impl From<u8> for Numeric {
1201 #[inline]
1202 fn from(value: u8) -> Self {
1203 Self::Number(value.into())
1204 }
1205}
1206
1207impl From<JsBigInt> for Numeric {
1208 #[inline]
1209 fn from(value: JsBigInt) -> Self {
1210 Self::BigInt(value)
1211 }
1212}
1213
1214impl From<Numeric> for JsValue {
1215 fn from(value: Numeric) -> Self {
1216 match value {
1217 Numeric::Number(number) => Self::new(number),
1218 Numeric::BigInt(bigint) => Self::new(bigint),
1219 }
1220 }
1221}