1use crate::facades::QuickjsRuntimeFacadeInner;
2use crate::jsutils::{JsError, JsValueType};
3use crate::quickjsrealmadapter::QuickJsRealmAdapter;
4use crate::quickjsvalueadapter::QuickJsValueAdapter;
5use crate::reflection::JsProxyInstanceId;
6use futures::executor::block_on;
7use futures::Future;
8use hirofa_utils::debug_mutex::DebugMutex;
9use serde::Serialize;
10use serde_json::Value;
11use std::collections::HashMap;
12use std::error::Error;
13use std::fmt::{Debug, Formatter};
14use std::pin::Pin;
15use std::sync::atomic::{AtomicU16, Ordering};
16use std::sync::{Arc, Weak};
17use std::time::Duration;
18use string_cache::DefaultAtom;
19
20pub struct CachedJsObjectRef {
21 pub(crate) id: i32,
22 rti: Weak<QuickjsRuntimeFacadeInner>,
23 realm_id: String,
24 drop_action: DebugMutex<Option<Box<dyn FnOnce() + Send>>>,
25}
26
27pub struct CachedJsPromiseRef {
28 pub cached_object: CachedJsObjectRef,
29}
30
31pub struct CachedJsArrayRef {
32 pub cached_object: CachedJsObjectRef,
33}
34
35pub struct CachedJsFunctionRef {
36 pub cached_object: CachedJsObjectRef,
37}
38
39impl CachedJsObjectRef {
40 pub(crate) fn new(realm: &QuickJsRealmAdapter, obj: QuickJsValueAdapter) -> Self {
41 let id = realm.cache_object(obj);
42 let rti_ref = realm.get_runtime_facade_inner();
43
44 let drop_id = id;
45 let drop_realm_name = realm.get_realm_id().to_string();
46
47 Self::new2(
48 id,
49 rti_ref.clone(),
50 realm.get_realm_id().to_string(),
51 move || {
52 if let Some(rti) = rti_ref.upgrade() {
53 rti.add_rt_task_to_event_loop_void(move |rt| {
54 if let Some(realm) = rt.get_realm(drop_realm_name.as_str()) {
55 realm.dispose_cached_object(drop_id);
56 }
57 })
58 }
59 },
60 )
61 }
62 fn new2<F: FnOnce() + Send + 'static>(
63 id: i32,
64 rti: Weak<QuickjsRuntimeFacadeInner>,
65 realm_name: String,
66 drop_action: F,
67 ) -> Self {
68 Self {
69 id,
70 rti,
71 realm_id: realm_name,
72 drop_action: DebugMutex::new(
73 Some(Box::new(drop_action)),
74 "CachedJsObjectRef.drop_action",
75 ),
76 }
77 }
78 pub async fn to_json_string(&self) -> Result<String, JsError> {
79 let id = self.id;
80 let realm_name = self.realm_id.clone();
81 let rti = self.rti.upgrade().expect("invalid state");
82 rti.add_rt_task_to_event_loop(move |rt| {
83 if let Some(realm) = rt.get_realm(realm_name.as_str()) {
84 realm.with_cached_object(id, |obj| realm.json_stringify(obj, None))
86 } else {
87 Err(JsError::new_str("no such realm"))
88 }
89 })
90 .await
91 }
92 pub fn get_object_sync(&self) -> Result<HashMap<String, JsValueFacade>, JsError> {
93 block_on(self.get_object())
94 }
95
96 pub async fn get_object(&self) -> Result<HashMap<String, JsValueFacade>, JsError> {
97 let id = self.id;
98 let realm_name = self.realm_id.clone();
99 let rti = self.rti.upgrade().expect("invalid state");
100 rti.add_rt_task_to_event_loop(move |rt| {
101 if let Some(realm) = rt.get_realm(realm_name.as_str()) {
102 let mut ret = HashMap::new();
104 let results = realm.with_cached_object(id, |obj| {
105 realm.traverse_object(obj, |name, value| {
106 Ok((name.to_string(), realm.to_js_value_facade(value)))
108 })
109 })?;
110 for result in results {
111 ret.insert(result.0, result.1?);
112 }
113 Ok(ret)
114 } else {
115 Err(JsError::new_str("no such realm"))
116 }
117 })
118 .await
119 }
120 pub async fn get_serde_value(&self) -> Result<serde_json::Value, JsError> {
121 let id = self.id;
122 let realm_name = self.realm_id.clone();
123 let rti = self.rti.upgrade().expect("invalid state");
124 rti.add_rt_task_to_event_loop(move |rt| {
125 if let Some(realm) = rt.get_realm(realm_name.as_str()) {
126 realm.with_cached_object(id, |obj| realm.value_adapter_to_serde_value(obj))
127 } else {
128 Err(JsError::new_str("no such realm"))
129 }
130 })
131 .await
132 }
133 pub fn with_obj_sync<
134 S: Send + 'static,
135 C: FnOnce(&QuickJsRealmAdapter, &QuickJsValueAdapter) -> S + Send + 'static,
136 >(
137 &self,
138 consumer: C,
139 ) -> Result<S, JsError> {
140 let id = self.id;
141 let realm_id = self.realm_id.clone();
142 let rti = self.rti.upgrade().expect("invalid state");
143 rti.exe_rt_task_in_event_loop(move |rt| {
144 if let Some(realm) = rt.get_realm(realm_id.as_str()) {
145 Ok(realm.with_cached_object(id, |obj| consumer(realm, obj)))
146 } else {
147 Err(JsError::new_str("Realm was disposed"))
148 }
149 })
150 }
151 pub fn with_obj_void<
152 S: Send + 'static,
153 C: FnOnce(&QuickJsRealmAdapter, &QuickJsValueAdapter) -> S + Send + 'static,
154 >(
155 &self,
156 consumer: C,
157 ) {
158 let id = self.id;
159 let realm_id = self.realm_id.clone();
160 let rti = self.rti.upgrade().expect("invalid state");
161 rti.add_rt_task_to_event_loop_void(move |rt| {
162 if let Some(realm) = rt.get_realm(realm_id.as_str()) {
163 realm.with_cached_object(id, |obj| consumer(realm, obj));
164 } else {
165 log::error!("no such realm");
166 }
167 })
168 }
169 pub async fn with_obj<
170 S: Send + 'static,
171 C: FnOnce(&QuickJsRealmAdapter, &QuickJsValueAdapter) -> S + Send + 'static,
172 >(
173 &self,
174 consumer: C,
175 ) -> Result<S, JsError> {
176 let id = self.id;
177 let realm_id = self.realm_id.clone();
178 let rti = self.rti.upgrade().expect("invalid state");
179 rti.add_rt_task_to_event_loop(move |rt| {
180 if let Some(realm) = rt.get_realm(realm_id.as_str()) {
181 Ok(realm.with_cached_object(id, |obj| consumer(realm, obj)))
182 } else {
183 Err(JsError::new_str("Realm was disposed"))
184 }
185 })
186 .await
187 }
188}
189
190impl Drop for CachedJsObjectRef {
191 fn drop(&mut self) {
192 let lck = &mut *self.drop_action.lock("drop").unwrap();
193 if let Some(da) = lck.take() {
194 da();
195 }
196 }
197}
198
199impl CachedJsPromiseRef {
200 pub async fn get_serde_value(&self) -> Result<serde_json::Value, JsError> {
201 self.cached_object.get_serde_value().await
202 }
203 pub async fn to_json_string(&self) -> Result<String, JsError> {
204 self.cached_object.to_json_string().await
205 }
206
207 pub fn get_promise_result_sync(&self) -> Result<Result<JsValueFacade, JsValueFacade>, JsError> {
208 let rx = self.get_promise_result_receiver();
209 rx.recv()
210 .map_err(|e| JsError::new_string(format!("get_promise_result_sync/1: {e}")))?
211 }
212
213 pub fn get_promise_result_sync_timeout(
214 &self,
215 timeout: Option<Duration>,
216 ) -> Result<Result<JsValueFacade, JsValueFacade>, JsError> {
217 let rx = self.get_promise_result_receiver();
218 let res = if let Some(timeout) = timeout {
219 rx.recv_timeout(timeout)
220 .map_err(|e| JsError::new_string(format!("get_promise_result_sync_timeout/1: {e}")))
221 } else {
222 rx.recv()
223 .map_err(|e| JsError::new_string(format!("get_promise_result_sync_timeout/2: {e}")))
224 };
225 res?
226 }
227
228 pub async fn get_promise_result(
229 &self,
230 ) -> Result<Result<JsValueFacade, JsValueFacade>, JsError> {
231 let rx = self.get_promise_result_receiver();
232 rx.into_recv_async()
233 .await
234 .map_err(|e| JsError::new_string(format!("{e}")))?
235 }
236
237 pub fn get_promise_result_receiver(
238 &self,
239 ) -> flume::Receiver<Result<Result<JsValueFacade, JsValueFacade>, JsError>> {
240 let (tx, rx) = flume::bounded(1);
241
242 let tx1 = tx.clone();
243 let tx2 = tx.clone();
244
245 let state = Arc::new(AtomicU16::new(0));
246 let state_then = state.clone();
247 let state_catch = state.clone();
248
249 self.cached_object.with_obj_void(move |realm, obj| {
250 let res = || {
251 let then_func = realm.create_function(
252 "then",
253 move |realm, _this, args| {
254 state_then.fetch_add(1, Ordering::Relaxed);
257
258 let resolution = &args[0];
259 let send_res = match realm.to_js_value_facade(resolution) {
260 Ok(vf) => tx1.send(Ok(Ok(vf))),
261 Err(conv_err) => tx1.send(Err(conv_err)),
262 };
263
264 send_res.map_err(|e| {
265 JsError::new_string(format!(
266 "could not send: {e} state:{}",
267 state_then.load(Ordering::Relaxed)
268 ))
269 })?;
270 realm.create_undefined()
271 },
272 1,
273 )?;
274 let catch_func = realm.create_function(
275 "catch",
276 move |realm, _this, args| {
277 state_catch.fetch_add(16, Ordering::Relaxed);
280
281 let rejection = &args[0];
282 let send_res = match realm.to_js_value_facade(rejection) {
283 Ok(vf) => tx2.send(Ok(Err(vf))),
284 Err(conv_err) => tx2.send(Err(conv_err)),
285 };
286
287 send_res.map_err(|e| {
288 JsError::new_string(format!(
289 "could not send: {e} state:{}",
290 state_catch.load(Ordering::Relaxed)
291 ))
292 })?;
293 realm.create_undefined()
294 },
295 1,
296 )?;
297
298 realm.add_promise_reactions(obj, Some(then_func), Some(catch_func), None)?;
299 Ok(())
300 };
301 match res() {
302 Ok(_) => {}
303 Err(e) => {
304 state.fetch_add(64, Ordering::Relaxed);
305 log::error!("failed to add promise reactions {}", e);
306 match tx.send(Err(e)) {
307 Ok(_) => {}
308 Err(e) => {
309 log::error!("failed to resolve 47643: {}", e);
310 }
311 }
312 }
313 }
314 });
315
316 rx
317 }
318}
319
320impl CachedJsArrayRef {
321 pub async fn get_serde_value(&self) -> Result<serde_json::Value, JsError> {
322 self.cached_object.get_serde_value().await
323 }
324 pub async fn to_json_string(&self) -> Result<String, JsError> {
325 self.cached_object.to_json_string().await
326 }
327 pub async fn get_array(&self) -> Result<Vec<JsValueFacade>, JsError> {
328 self.cached_object
329 .with_obj(|realm, arr| {
330 let mut vec: Vec<JsValueFacade> = vec![];
331 realm.traverse_array_mut(arr, |_index, element| {
332 vec.push(realm.to_js_value_facade(element)?);
333 Ok(())
334 })?;
335 Ok(vec)
336 })
337 .await?
338 }
339}
340
341impl CachedJsFunctionRef {
342 pub async fn get_serde_value(&self) -> Result<serde_json::Value, JsError> {
343 self.cached_object.get_serde_value().await
344 }
345
346 pub fn invoke_function(
347 &self,
348 args: Vec<JsValueFacade>,
349 ) -> impl Future<Output = Result<JsValueFacade, JsError>> + Send {
350 let cached_obj_id = self.cached_object.id;
352 let realm_id = self.cached_object.realm_id.clone();
353 let rti = self.cached_object.rti.upgrade().expect("invalid state");
354 rti.add_rt_task_to_event_loop(move |rt| {
355 if let Some(realm) = rt.get_realm(realm_id.as_str()) {
357 realm.with_cached_object(cached_obj_id, move |func_adapter| {
358 let mut adapter_args = vec![];
359 for arg in args {
360 adapter_args.push(realm.from_js_value_facade(arg)?);
361 }
362
363 let adapter_refs: Vec<&QuickJsValueAdapter> = adapter_args.iter().collect();
364
365 let val_adapter = realm.invoke_function(None, func_adapter, &adapter_refs)?;
366
367 realm.to_js_value_facade(&val_adapter)
368 })
369 } else {
370 Ok(JsValueFacade::Null)
371 }
372 })
373 }
374 pub fn invoke_function_sync(&self, args: Vec<JsValueFacade>) -> Result<JsValueFacade, JsError> {
375 self.cached_object.with_obj_sync(|realm, func_adapter| {
376 let mut adapter_args = vec![];
378 for arg in args {
379 adapter_args.push(realm.from_js_value_facade(arg)?);
380 }
381
382 let adapter_refs: Vec<&QuickJsValueAdapter> = adapter_args.iter().collect();
383
384 let val_adapter = realm.invoke_function(None, func_adapter, &adapter_refs)?;
385
386 realm.to_js_value_facade(&val_adapter)
387 })?
388 }
389}
390
391pub enum TypedArrayType {
392 Uint8,
393}
394
395#[allow(clippy::type_complexity)]
397pub enum JsValueFacade {
398 I32 {
399 val: i32,
400 },
401 F64 {
402 val: f64,
403 },
404 String {
405 val: DefaultAtom,
406 },
407 Boolean {
408 val: bool,
409 },
410 JsObject {
411 cached_object: CachedJsObjectRef,
413 },
414 JsPromise {
415 cached_promise: CachedJsPromiseRef,
416 },
417 JsArray {
418 cached_array: CachedJsArrayRef,
419 },
420 JsFunction {
421 cached_function: CachedJsFunctionRef,
422 },
423 Object {
425 val: HashMap<String, JsValueFacade>,
426 },
427 Array {
429 val: Vec<JsValueFacade>,
430 },
431 Promise {
433 producer: DebugMutex<
434 Option<Pin<Box<dyn Future<Output = Result<JsValueFacade, JsError>> + Send + 'static>>>,
435 >,
436 },
437 Function {
439 name: String,
440 arg_count: u32,
441 func: Arc<Box<dyn Fn(&[JsValueFacade]) -> Result<JsValueFacade, JsError> + Send + Sync>>,
442 },
443 JsError {
444 val: JsError,
445 },
446 ProxyInstance {
447 namespace: &'static [&'static str],
448 class_name: &'static str,
449 instance_id: JsProxyInstanceId,
450 },
451 TypedArray {
452 buffer: Vec<u8>,
453 array_type: TypedArrayType,
454 },
455 JsonStr {
456 json: String,
457 },
458 SerdeValue {
459 value: serde_json::Value,
460 },
461 Null,
462 Undefined,
463}
464
465impl JsValueFacade {
466 pub fn from_serializable<T: Serialize>(obj: &T) -> Result<Self, Box<dyn Error>> {
467 let json = serde_json::to_string(obj)?;
468 Ok(Self::JsonStr { json })
469 }
470
471 pub fn new_i32(val: i32) -> Self {
472 Self::I32 { val }
473 }
474 pub fn new_f64(val: f64) -> Self {
475 Self::F64 { val }
476 }
477 pub fn new_bool(val: bool) -> Self {
478 Self::Boolean { val }
479 }
480 pub fn new_str_atom(val: DefaultAtom) -> Self {
481 Self::String { val }
482 }
483 pub fn new_str(val: &str) -> Self {
484 Self::String {
485 val: DefaultAtom::from(val),
486 }
487 }
488 pub fn new_string(val: String) -> Self {
489 Self::String {
490 val: DefaultAtom::from(val),
491 }
492 }
493 pub fn new_callback<
494 F: Fn(&[JsValueFacade]) -> Result<JsValueFacade, JsError> + Send + Sync + 'static,
495 >(
496 callback: F,
497 ) -> Self {
498 Self::Function {
499 name: "".to_string(),
500 arg_count: 0,
501 func: Arc::new(Box::new(callback)),
502 }
503 }
504 pub fn new_function<
505 F: Fn(&[JsValueFacade]) -> Result<JsValueFacade, JsError> + Send + Sync + 'static,
506 >(
507 name: &str,
508 function: F,
509 arg_count: u32,
510 ) -> Self {
511 Self::Function {
512 name: name.to_string(),
513 arg_count,
514 func: Arc::new(Box::new(function)),
515 }
516 }
517 pub fn new_promise<R, P, M>(producer: P) -> Self
519 where
520 P: Future<Output = Result<JsValueFacade, JsError>> + Send + 'static,
521 {
522 JsValueFacade::Promise {
523 producer: DebugMutex::new(Some(Box::pin(producer)), "JsValueFacade::Promise.producer"),
524 }
525 }
526
527 pub fn is_i32(&self) -> bool {
528 matches!(self, JsValueFacade::I32 { .. })
529 }
530 pub fn is_f64(&self) -> bool {
531 matches!(self, JsValueFacade::F64 { .. })
532 }
533 pub fn is_bool(&self) -> bool {
534 matches!(self, JsValueFacade::Boolean { .. })
535 }
536 pub fn is_string(&self) -> bool {
537 matches!(self, JsValueFacade::String { .. })
538 }
539 pub fn is_js_promise(&self) -> bool {
540 matches!(self, JsValueFacade::JsPromise { .. })
541 }
542 pub fn is_js_object(&self) -> bool {
543 matches!(self, JsValueFacade::JsObject { .. })
544 }
545 pub fn is_js_array(&self) -> bool {
546 matches!(self, JsValueFacade::JsArray { .. })
547 }
548
549 pub fn get_i32(&self) -> i32 {
550 match self {
551 JsValueFacade::I32 { val } => *val,
552 _ => {
553 panic!("Not an i32");
554 }
555 }
556 }
557 pub fn get_f64(&self) -> f64 {
558 match self {
559 JsValueFacade::F64 { val } => *val,
560 _ => {
561 panic!("Not an f64");
562 }
563 }
564 }
565 pub fn get_bool(&self) -> bool {
566 match self {
567 JsValueFacade::Boolean { val } => *val,
568 _ => {
569 panic!("Not a boolean");
570 }
571 }
572 }
573 pub fn get_str(&self) -> &str {
574 match self {
575 JsValueFacade::String { val } => val,
576 _ => {
577 panic!("Not a string");
578 }
579 }
580 }
581 pub fn get_str_atom(&self) -> &DefaultAtom {
582 match self {
583 JsValueFacade::String { val } => val,
584 _ => {
585 panic!("Not a string");
586 }
587 }
588 }
589 pub fn is_null_or_undefined(&self) -> bool {
590 matches!(self, JsValueFacade::Null | JsValueFacade::Undefined)
591 }
592 pub fn get_value_type(&self) -> JsValueType {
593 match self {
594 JsValueFacade::I32 { .. } => JsValueType::I32,
595 JsValueFacade::F64 { .. } => JsValueType::F64,
596 JsValueFacade::String { .. } => JsValueType::String,
597 JsValueFacade::Boolean { .. } => JsValueType::Boolean,
598 JsValueFacade::JsObject { .. } => JsValueType::Object,
599 JsValueFacade::Null => JsValueType::Null,
600 JsValueFacade::Undefined => JsValueType::Undefined,
601 JsValueFacade::Object { .. } => JsValueType::Object,
602 JsValueFacade::Array { .. } => JsValueType::Array,
603 JsValueFacade::Promise { .. } => JsValueType::Promise,
604 JsValueFacade::Function { .. } => JsValueType::Function,
605 JsValueFacade::JsPromise { .. } => JsValueType::Promise,
606 JsValueFacade::JsArray { .. } => JsValueType::Array,
607 JsValueFacade::JsFunction { .. } => JsValueType::Function,
608 JsValueFacade::JsError { .. } => JsValueType::Error,
609 JsValueFacade::ProxyInstance { .. } => JsValueType::Object,
610 JsValueFacade::TypedArray { .. } => JsValueType::Object,
611 JsValueFacade::JsonStr { .. } => JsValueType::Object,
612 JsValueFacade::SerdeValue { value } => match value {
613 serde_json::Value::Null => JsValueType::Null,
614 serde_json::Value::Bool(_) => JsValueType::Boolean,
615 serde_json::Value::Number(_) => {
616 if value.is_i64() {
617 let num = value.as_i64().unwrap();
618 if num <= i32::MAX as i64 {
619 JsValueType::I32
620 } else {
621 JsValueType::F64
622 }
623 } else if value.is_f64() {
624 JsValueType::F64
625 } else {
626 let num = value.as_u64().unwrap();
628 if num <= i32::MAX as u64 {
629 JsValueType::I32
630 } else {
631 JsValueType::F64
632 }
633 }
634 }
635 serde_json::Value::String(_) => JsValueType::String,
636 serde_json::Value::Array(_) => JsValueType::Array,
637 serde_json::Value::Object(_) => JsValueType::Object,
638 },
639 }
640 }
641 pub fn stringify(&self) -> String {
642 match self {
643 JsValueFacade::I32 { val } => {
644 format!("I32: {val}")
645 }
646 JsValueFacade::F64 { val } => {
647 format!("F64: {val}")
648 }
649 JsValueFacade::String { val } => {
650 format!("String: {val}")
651 }
652 JsValueFacade::Boolean { val } => {
653 format!("Boolean: {val}")
654 }
655 JsValueFacade::JsObject { cached_object } => {
656 format!(
657 "JsObject: [{}.{}]",
658 cached_object.realm_id, cached_object.id
659 )
660 }
661 JsValueFacade::JsPromise { cached_promise } => {
662 format!(
663 "JsPromise: [{}.{}]",
664 cached_promise.cached_object.realm_id, cached_promise.cached_object.id
665 )
666 }
667 JsValueFacade::JsArray { cached_array } => {
668 format!(
669 "JsArray: [{}.{}]",
670 cached_array.cached_object.realm_id, cached_array.cached_object.id
671 )
672 }
673 JsValueFacade::JsFunction { cached_function } => {
674 format!(
675 "JsFunction: [{}.{}]",
676 cached_function.cached_object.realm_id, cached_function.cached_object.id
677 )
678 }
679 JsValueFacade::Object { val } => {
680 format!("Object: [len={}]", val.keys().len())
681 }
682 JsValueFacade::Array { val } => {
683 format!("Array: [len={}]", val.len())
684 }
685 JsValueFacade::Promise { .. } => "Promise".to_string(),
686 JsValueFacade::Function { .. } => "Function".to_string(),
687 JsValueFacade::Null => "Null".to_string(),
688 JsValueFacade::Undefined => "Undefined".to_string(),
689 JsValueFacade::JsError { val } => format!("{val}"),
690 JsValueFacade::ProxyInstance { .. } => "ProxyInstance".to_string(),
691 JsValueFacade::TypedArray { .. } => "TypedArray".to_string(),
692 JsValueFacade::JsonStr { json } => format!("JsonStr: '{json}'"),
693 JsValueFacade::SerdeValue { value } => format!("Serde value: {value}"),
694 }
695 }
696 pub async fn to_serde_value(&self) -> Result<serde_json::Value, JsError> {
697 match self {
698 JsValueFacade::I32 { val } => Ok(serde_json::Value::from(*val)),
699 JsValueFacade::F64 { val } => Ok(serde_json::Value::from(*val)),
700 JsValueFacade::String { val } => Ok(serde_json::Value::from(val.to_string())),
701 JsValueFacade::Boolean { val } => Ok(serde_json::Value::from(*val)),
702 JsValueFacade::JsObject { cached_object } => cached_object.get_serde_value().await,
703 JsValueFacade::JsPromise { cached_promise } => cached_promise.get_serde_value().await,
704 JsValueFacade::JsArray { cached_array } => cached_array.get_serde_value().await,
705 JsValueFacade::JsFunction { .. } => Ok(Value::Null),
706 JsValueFacade::Object { .. } => Ok(Value::Null),
707 JsValueFacade::Array { .. } => Ok(Value::Null),
708 JsValueFacade::Promise { .. } => Ok(Value::Null),
709 JsValueFacade::Function { .. } => Ok(Value::Null),
710 JsValueFacade::Null => Ok(Value::Null),
711 JsValueFacade::Undefined => Ok(Value::Null),
712 JsValueFacade::JsError { .. } => Ok(Value::Null),
713 JsValueFacade::ProxyInstance { .. } => Ok(Value::Null),
714 JsValueFacade::TypedArray { .. } => Ok(Value::Null),
715 JsValueFacade::JsonStr { json } => Ok(serde_json::from_str(json).unwrap()),
716 JsValueFacade::SerdeValue { value } => Ok(value.clone()),
717 }
718 }
719 pub async fn to_json_string(&self) -> Result<String, JsError> {
720 match self {
721 JsValueFacade::I32 { val } => Ok(format!("{val}")),
722 JsValueFacade::F64 { val } => Ok(format!("{val}")),
723 JsValueFacade::String { val } => Ok(format!("'{}'", val.replace('\'', "\\'"))),
724 JsValueFacade::Boolean { val } => Ok(format!("{val}")),
725 JsValueFacade::JsObject { cached_object } => cached_object.to_json_string().await,
726 JsValueFacade::JsPromise { cached_promise } => cached_promise.to_json_string().await,
727 JsValueFacade::JsArray { cached_array } => cached_array.to_json_string().await,
728 JsValueFacade::JsFunction { .. } => Ok("function () {}".to_string()),
729 JsValueFacade::Object { .. } => Ok("{}".to_string()),
730 JsValueFacade::Array { .. } => Ok("{}".to_string()),
731 JsValueFacade::Promise { .. } => Ok("{}".to_string()),
732 JsValueFacade::Function { .. } => Ok("function () {}".to_string()),
733 JsValueFacade::Null => Ok("null".to_string()),
734 JsValueFacade::Undefined => Ok("undefined".to_string()),
735 JsValueFacade::JsError { val } => Ok(format!("'{val}'")),
736 JsValueFacade::ProxyInstance { .. } => Ok("{}".to_string()),
737 JsValueFacade::TypedArray { .. } => Ok("[]".to_string()),
738 JsValueFacade::JsonStr { json } => Ok(json.clone()),
739 JsValueFacade::SerdeValue { value } => Ok(serde_json::to_string(value).unwrap()),
740 }
741 }
742}
743
744impl Debug for JsValueFacade {
745 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
746 f.write_str(self.stringify().as_str())
747 }
748}
749
750pub trait JsValueConvertable {
751 fn to_js_value_facade(self) -> JsValueFacade;
752}
753
754impl JsValueConvertable for serde_json::Value {
755 fn to_js_value_facade(self) -> JsValueFacade {
756 JsValueFacade::SerdeValue { value: self }
757 }
758}
759
760impl JsValueConvertable for bool {
761 fn to_js_value_facade(self) -> JsValueFacade {
762 JsValueFacade::new_bool(self)
763 }
764}
765
766impl JsValueConvertable for i32 {
767 fn to_js_value_facade(self) -> JsValueFacade {
768 JsValueFacade::new_i32(self)
769 }
770}
771
772impl JsValueConvertable for f64 {
773 fn to_js_value_facade(self) -> JsValueFacade {
774 JsValueFacade::new_f64(self)
775 }
776}
777
778impl JsValueConvertable for &str {
779 fn to_js_value_facade(self) -> JsValueFacade {
780 JsValueFacade::new_str(self)
781 }
782}
783
784impl JsValueConvertable for String {
785 fn to_js_value_facade(self) -> JsValueFacade {
786 JsValueFacade::new_string(self)
787 }
788}
789
790impl JsValueConvertable for Vec<u8> {
791 fn to_js_value_facade(self) -> JsValueFacade {
792 JsValueFacade::TypedArray {
793 buffer: self,
794 array_type: TypedArrayType::Uint8,
795 }
796 }
797}
798
799impl JsValueConvertable for Vec<JsValueFacade> {
800 fn to_js_value_facade(self) -> JsValueFacade {
801 JsValueFacade::Array { val: self }
802 }
803}
804
805impl JsValueConvertable for HashMap<String, JsValueFacade> {
806 fn to_js_value_facade(self) -> JsValueFacade {
807 JsValueFacade::Object { val: self }
808 }
809}
810