quickjs_runtime/
values.rs

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                //let realm: JsRealmAdapter<JsRuntimeAdapterType = (), JsValueAdapterType = ()> = realm;
85                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 realm: JsRealmAdapter = realm;
103                let mut ret = HashMap::new();
104                let results = realm.with_cached_object(id, |obj| {
105                    realm.traverse_object(obj, |name, value| {
106                        //
107                        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                        //
255
256                        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                        //
278
279                        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        //Pin<Box<dyn futures::Future<Output = Result<JsValueFacade, JsError>>>>
351        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            //
356            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            //
377            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/// The JsValueFacade is a Send-able representation of a value in the Script engine
396#[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        // obj which is a ref to obj in Js
412        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    // obj created from rust
424    Object {
425        val: HashMap<String, JsValueFacade>,
426    },
427    // array created from rust
428    Array {
429        val: Vec<JsValueFacade>,
430    },
431    // promise created from rust which will run an async producer
432    Promise {
433        producer: DebugMutex<
434            Option<Pin<Box<dyn Future<Output = Result<JsValueFacade, JsError>> + Send + 'static>>>,
435        >,
436    },
437    // Function created from rust
438    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    /// create a new promise with a producer which will run async in a threadpool
518    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                        // u64
627                        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/* todo
811impl JsValueConvertable for Fn(&[JsValueFacade]) -> Result<JsValueFacade, JsError> + Send + Sync {
812    fn to_js_value_facade(self) -> JsValueFacade {
813        JsValueFacade::Function {
814            name: "".to_string(),
815            arg_count: 0,
816            func: Arc::new(Box::new(self)),
817        }
818    }
819}
820 */