Skip to main content

boa_engine/value/conversions/
mod.rs

1//! Conversions from JavaScript values into Rust values, and the other way around.
2
3use super::{JsBigInt, JsObject, JsString, JsSymbol, JsValue};
4use crate::NativeObject;
5use crate::value::inner::InnerValue;
6use crate::{js_string, string::JsStr};
7
8mod either;
9pub(super) mod nullable;
10mod serde_json;
11pub(super) mod try_from_js;
12pub(super) mod try_into_js;
13
14pub(super) mod convert;
15
16impl From<JsStr<'_>> for JsValue {
17    fn from(value: JsStr<'_>) -> Self {
18        Self::from_inner(InnerValue::string(value.into()))
19    }
20}
21
22impl From<JsString> for JsValue {
23    fn from(value: JsString) -> Self {
24        Self::from_inner(InnerValue::string(value))
25    }
26}
27
28impl From<char> for JsValue {
29    #[inline]
30    fn from(value: char) -> Self {
31        let mut buf: [u16; 2] = [0; 2];
32
33        let out = value.encode_utf16(&mut buf);
34
35        Self::from(js_string!(&*out))
36    }
37}
38
39impl From<JsSymbol> for JsValue {
40    #[inline]
41    fn from(value: JsSymbol) -> Self {
42        Self::from_inner(InnerValue::symbol(value))
43    }
44}
45
46impl From<f32> for JsValue {
47    #[inline]
48    fn from(value: f32) -> Self {
49        Self::rational(f64::from(value))
50    }
51}
52
53impl From<f64> for JsValue {
54    #[inline]
55    fn from(value: f64) -> Self {
56        Self::rational(value)
57    }
58}
59
60macro_rules! impl_from_integer {
61    ( $( $type_:ty ),* ) => {
62        $(
63            impl From<$type_> for JsValue {
64                #[inline]
65                #[allow(clippy::cast_lossless)]
66                fn from(value: $type_) -> Self {
67
68                    i32::try_from(value)
69                        .map_or_else(
70                            |_| Self::rational(value as f64),
71                            |value| Self::from_inner(InnerValue::integer32(value)),
72                        )
73                }
74            }
75        )*
76    };
77}
78
79impl_from_integer!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize);
80
81impl From<JsBigInt> for JsValue {
82    #[inline]
83    fn from(value: JsBigInt) -> Self {
84        Self::from_inner(InnerValue::bigint(value))
85    }
86}
87
88impl From<bool> for JsValue {
89    #[inline]
90    fn from(value: bool) -> Self {
91        Self::from_inner(InnerValue::boolean(value))
92    }
93}
94
95impl<T: NativeObject> From<JsObject<T>> for JsValue {
96    #[inline]
97    fn from(object: JsObject<T>) -> Self {
98        Self::from_inner(InnerValue::object(object.upcast()))
99    }
100}
101
102impl From<()> for JsValue {
103    #[inline]
104    #[allow(clippy::pedantic)] // didn't want to increase our MSRV for just a lint.
105    fn from((): ()) -> Self {
106        Self::null()
107    }
108}
109
110/// Converts an `Option<T>` into a `JsValue`.
111///
112/// It will convert the `None` variant to `JsValue::undefined()`, and the `Some()` variant into a
113/// `JsValue` using the `Into` trait.
114pub(crate) trait IntoOrUndefined {
115    /// Converts an `Option<T>` into a `JsValue`.
116    fn into_or_undefined(self) -> JsValue;
117}
118
119impl<T> IntoOrUndefined for Option<T>
120where
121    T: Into<JsValue>,
122{
123    #[inline]
124    fn into_or_undefined(self) -> JsValue {
125        match self {
126            Some(value) => value.into(),
127            None => JsValue::undefined(),
128        }
129    }
130}