1use crate::{JSContext, JSContextImpl, JSResult, RongJSError};
2use std::fmt;
3use std::hash::Hash;
4
5mod convert;
6pub use convert::*;
7
8mod error;
9pub use error::*;
10
11mod exception;
12pub use exception::*;
13
14mod valuetype;
15pub use valuetype::{JSTypeOf, JSValueType};
16
17mod object;
18pub use object::*;
19
20mod array;
21pub use array::*;
22
23mod array_buffer;
24pub use array_buffer::*;
25
26mod bytes;
27pub(crate) use bytes::JSBytesData;
28pub use bytes::*;
29
30mod typed_array;
31pub use typed_array::*;
32
33mod function;
34pub use function::*;
35
36mod symbol;
37pub use symbol::*;
38
39mod date;
40pub use date::*;
41
42mod proxy;
43pub use proxy::*;
44
45pub trait JSValueImpl: Clone + PartialEq + Hash {
46 type RawValue: Copy;
48
49 type Context: JSContextImpl<Value = Self>;
52
53 fn from_borrowed_raw(
56 ctx: <Self::Context as JSContextImpl>::RawContext,
57 value: Self::RawValue,
58 ) -> Self;
59
60 fn from_owned_raw(
63 ctx: <Self::Context as JSContextImpl>::RawContext,
64 value: Self::RawValue,
65 ) -> Self;
66
67 fn into_raw_value(self) -> Self::RawValue;
70
71 fn as_raw_value(&self) -> &Self::RawValue;
72 fn raw_value_for_api(&self) -> Self::RawValue {
73 *self.as_raw_value()
74 }
75 fn as_raw_context(&self) -> &<Self::Context as JSContextImpl>::RawContext;
76
77 fn create_null(ctx: &Self::Context) -> Self;
79
80 fn create_undefined(ctx: &Self::Context) -> Self;
82
83 fn create_symbol(ctx: &Self::Context, descripiton: &str) -> Self;
85
86 fn from_json_str(ctx: &Self::Context, str: &str) -> Self;
88
89 fn create_date(ctx: &Self::Context, epoch_ms: f64) -> Self;
91}
92
93pub struct JSValue<V: JSValueImpl> {
94 inner: V,
95}
96
97impl<V: JSValueImpl> Clone for JSValue<V> {
98 fn clone(&self) -> Self {
99 Self {
100 inner: self.inner.clone(),
101 }
102 }
103}
104
105impl<V: JSValueImpl> PartialEq for JSValue<V> {
106 fn eq(&self, other: &Self) -> bool {
107 self.inner.eq(&other.inner)
108 }
109}
110
111impl<V: JSValueImpl> Eq for JSValue<V> {}
112
113impl<V: JSValueImpl> Hash for JSValue<V> {
114 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
115 self.inner.hash(state);
116 }
117}
118
119impl<V> JSValue<V>
120where
121 V: JSValueImpl,
122{
123 pub fn from_raw(_ctx: &JSContext<V::Context>, value: V) -> Self {
124 Self { inner: value }
125 }
126
127 pub fn as_value(&self) -> &V {
128 &self.inner
129 }
130
131 pub fn into_value(self) -> V {
132 self.inner
133 }
134
135 pub fn context(&self) -> JSContext<V::Context> {
137 JSContext::from_borrowed_raw_ptr(self.as_value().as_raw_context())
138 }
139
140 pub fn from_rust<T>(ctx: &JSContext<V::Context>, val: T) -> Self
142 where
143 T: IntoJSValue<V>,
144 {
145 <T as IntoJSValue<V>>::into_js_value(val, ctx)
146 }
147
148 pub fn to_rust<T>(self) -> JSResult<T>
150 where
151 T: FromJSValue<V>,
152 {
153 let ctx = self.context();
154 T::from_js_value(&ctx, self)
155 }
156
157 pub fn undefined(ctx: &JSContext<V::Context>) -> Self {
159 let value = V::create_undefined(ctx.as_ref());
160 JSValue::from_raw(ctx, value)
161 }
162
163 pub fn null(ctx: &JSContext<V::Context>) -> Self {
165 let value = V::create_null(ctx.as_ref());
166 JSValue::from_raw(ctx, value)
167 }
168}
169
170impl<V> JSValue<V>
171where
172 V: JSValueImpl + JSTypeOf,
173{
174 pub fn into_object(self) -> Option<JSObject<V>> {
180 self.take_is_object().map(|v| v.into())
181 }
182}
183
184impl<V> FromJSValue<V> for JSValue<V>
185where
186 V: JSValueImpl,
187{
188 fn from_js_value(_ctx: &JSContext<V::Context>, value: JSValue<V>) -> JSResult<Self> {
189 Ok(value)
190 }
191}
192
193impl<V> IntoJSValue<V> for JSValue<V>
194where
195 V: JSValueImpl,
196{
197 fn into_js_value(self, _ctx: &JSContext<V::Context>) -> JSValue<V> {
198 self
199 }
200}
201
202pub trait JsonToJSValue<V>
204where
205 V: JSValueImpl,
206{
207 fn json_to_js_value(self, ctx: &JSContext<V::Context>) -> JSResult<JSValue<V>>;
209}
210
211impl<V> JsonToJSValue<V> for &str
212where
213 V: JSObjectOps + JSTypeOf,
214{
215 fn json_to_js_value(self, ctx: &JSContext<V::Context>) -> JSResult<JSValue<V>> {
216 let result = V::from_json_str(ctx.as_ref(), self);
217 result.try_map(|v| JSValue::from_raw(ctx, v))
218 }
219}
220
221pub trait JSValueMapper<V: JSValueImpl> {
223 fn try_convert<T>(self) -> JSResult<T>
225 where
226 T: FromJSValue<V>;
227
228 fn try_map<T, F>(self, f: F) -> JSResult<T>
231 where
232 F: FnOnce(Self) -> T,
233 Self: Sized;
234}
235
236impl<V> JSValueMapper<V> for V
237where
238 V: JSTypeOf,
239 V: JSObjectOps,
240{
241 fn try_convert<T>(self) -> JSResult<T>
242 where
243 T: FromJSValue<V>,
244 {
245 self.try_map(|value| {
246 let ctx = JSContext::from_borrowed_raw_ptr(value.as_raw_context());
247 T::from_js_value(&ctx, JSValue::from_raw(&ctx, value))
248 })?
249 }
250
251 fn try_map<T, F>(self, f: F) -> JSResult<T>
252 where
253 F: FnOnce(Self) -> T,
254 {
255 if self.is_exception() {
256 let ctx: JSContext<V::Context> =
257 JSContext::from_borrowed_raw_ptr(self.as_raw_context());
258 Err(RongJSError::from_thrown_value(JSValue::from_raw(
259 &ctx, self,
260 )))
261 } else {
262 Ok(f(self))
263 }
264 }
265}
266
267#[macro_export]
268macro_rules! impl_js_converter {
269 ($target:ty, $in_type:ty, $out_type:ty, $create_fn:expr, $to_fn:expr) => {
270 impl TryInto<$out_type> for $target
271 where
272 Self: JSValueImpl,
273 {
274 type Error = RongJSError;
275 fn try_into(self) -> Result<$out_type, Self::Error> {
276 let mut result: $out_type = Default::default();
277 if unsafe {
278 $to_fn(
279 *self.as_raw_context(),
280 self.raw_value_for_api(),
281 &mut result,
282 )
283 } < 0
284 {
285 Err($crate::HostError::new(
286 $crate::error::E_TYPE,
287 format!(
288 "Expected JSValue to be type {}, but got {:?}",
289 std::any::type_name::<$out_type>(),
290 self.type_of()
291 ),
292 )
293 .with_name("TypeError")
294 .into())
295 } else {
296 Ok(result)
297 }
298 }
299 }
300
301 impl<T> From<(&T, $in_type)> for $target
302 where
303 T: JSContextImpl<RawContext = <$target as JSRawContext>::RawContext>,
304 $target: JSValueImpl<Context = T>,
305 {
306 fn from(t: (&T, $in_type)) -> Self {
307 let ctx = t.0.as_raw();
308 let raw = unsafe { $create_fn(*ctx, t.1) };
309 Self::from_owned_raw(*ctx, raw)
310 }
311 }
312 };
313
314 ($target:ty, $type:ty, $create_fn:expr, $to_fn:expr) => {
315 impl_js_converter!($target, $type, $type, $create_fn, $to_fn);
316 };
317}
318
319impl<V: JSValueImpl> crate::function::JSParameterType for JSValue<V> {}
321
322impl<V> fmt::Display for JSValue<V>
323where
324 V: JSTypeOf + JSValueConversion,
325{
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327 match self.type_of() {
328 JSValueType::Boolean => {
329 if let Ok(val) = self.clone().to_rust::<bool>() {
330 write!(f, "{}", val)
331 } else {
332 write!(f, "boolean")
333 }
334 }
335 JSValueType::Number => {
336 if let Ok(val) = self.clone().to_rust::<f64>() {
337 write!(f, "{}", val)
338 } else {
339 write!(f, "number")
340 }
341 }
342 JSValueType::String => {
343 if let Ok(val) = self.clone().to_rust::<String>() {
344 write!(f, "{}", val)
345 } else {
346 write!(f, "string")
347 }
348 }
349 JSValueType::Date => {
350 if let Ok(val) = self.clone().to_rust::<String>() {
351 write!(f, "{}", val)
352 } else {
353 write!(f, "Date")
354 }
355 }
356 JSValueType::Undefined => write!(f, "undefined"),
357 JSValueType::Null => write!(f, "null"),
358 JSValueType::BigInt => write!(f, "bigint"),
359 JSValueType::Object => write!(f, "object"),
360 JSValueType::Array => write!(f, "array"),
361 JSValueType::ArrayBuffer => write!(f, "arrayBuffer"),
362 JSValueType::Function => write!(f, "function"),
363 JSValueType::Constructor => write!(f, "constructor"),
364 JSValueType::Promise => write!(f, "promise"),
365 JSValueType::Symbol => write!(f, "symbol"),
366 JSValueType::Error => write!(f, "error"),
367 JSValueType::Exception => write!(f, "exception"),
368 JSValueType::Unknown => write!(f, "unknown"),
369 }
370 }
371}
372
373impl<V> fmt::Debug for JSValue<V>
374where
375 V: JSTypeOf + JSValueConversion,
376{
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 write!(f, "JSValue({})", self)
379 }
380}