quickjs_rusty/value/
value.rs

1use std::collections::HashMap;
2use std::convert::TryFrom;
3use std::convert::TryInto;
4use std::hash::Hash;
5
6#[cfg(feature = "chrono")]
7use chrono::{DateTime, Utc};
8use libquickjs_ng_sys as q;
9
10#[cfg(feature = "bigint")]
11use crate::utils::create_bigint;
12#[cfg(feature = "chrono")]
13use crate::utils::create_date;
14use crate::utils::{
15    add_array_element, add_object_property, create_bool, create_empty_array, create_empty_object,
16    create_float, create_function, create_int, create_null, create_string,
17};
18use crate::OwnedJsPromise;
19use crate::{ExecutionError, ValueError};
20
21use super::tag::JsTag;
22use super::JsCompiledFunction;
23use super::JsFunction;
24use super::JsModule;
25use super::OwnedJsArray;
26use super::OwnedJsObject;
27
28/// OwnedJsValue wraps a Javascript value owned by the QuickJs runtime.
29///
30/// Guarantees cleanup of resources by dropping the value from the runtime.
31///
32/// **Safety**:
33///
34/// This type is `Send` and `Sync` only for convenience, since [OwnedJsValue](crate::OwnedJsValue)
35/// itself is just a wrapper around a raw pointer. But any operation on the underlying raw pointer is unsafe.
36/// Make sure using it in a same thread.
37///
38pub struct OwnedJsValue {
39    context: *mut q::JSContext,
40    // FIXME: make private again, just for testing
41    pub(crate) value: q::JSValue,
42}
43
44unsafe impl Send for OwnedJsValue {}
45unsafe impl Sync for OwnedJsValue {}
46
47impl PartialEq for OwnedJsValue {
48    fn eq(&self, other: &Self) -> bool {
49        unsafe { q::JS_Ext_GetPtr(self.value) == q::JS_Ext_GetPtr(other.value) }
50    }
51}
52
53impl OwnedJsValue {
54    #[inline]
55    pub fn context(&self) -> *mut q::JSContext {
56        self.context
57    }
58
59    /// Create a new `OwnedJsValue` from a `JsValue`.
60    /// This will **NOT** increase the ref count of the underlying value. So
61    /// you have to manage memory yourself. Be careful when using this.
62    #[inline]
63    pub fn new(context: *mut q::JSContext, value: q::JSValue) -> Self {
64        Self { context, value }
65    }
66
67    /// Create a new `OwnedJsValue` from a `JsValue`.
68    /// This will increase the ref count of the underlying value.
69    #[inline]
70    pub fn own(context: *mut q::JSContext, value: &q::JSValue) -> Self {
71        unsafe { q::JS_DupValue(context, *value) };
72        Self::new(context, *value)
73    }
74
75    #[inline]
76    pub fn tag(&self) -> JsTag {
77        JsTag::from_c(&self.value)
78    }
79
80    /// Get the inner JSValue without increasing ref count.
81    ///
82    /// Unsafe because the caller must ensure proper memory management.
83    pub unsafe fn as_inner(&self) -> &q::JSValue {
84        &self.value
85    }
86
87    /// Extract the underlying JSValue.
88    ///
89    /// Unsafe because the caller must ensure memory management. (eg JS_FreeValue)
90    pub unsafe fn extract(self) -> q::JSValue {
91        let v = self.value;
92        std::mem::forget(self);
93        v
94    }
95
96    /// Replace the underlying JSValue.
97    /// This will decrease the ref count of the old value but remain the ref count of the new value.
98    pub fn replace(&mut self, new: q::JSValue) {
99        unsafe {
100            q::JS_FreeValue(self.context, self.value);
101        }
102        self.value = new;
103    }
104
105    /// Check if this value is `null`.
106    #[inline]
107    pub fn is_null(&self) -> bool {
108        self.tag().is_null()
109    }
110
111    /// Check if this value is `undefined`.
112    #[inline]
113    pub fn is_undefined(&self) -> bool {
114        self.tag() == JsTag::Undefined
115    }
116
117    /// Check if this value is `bool`.
118    #[inline]
119    pub fn is_bool(&self) -> bool {
120        self.tag() == JsTag::Bool
121    }
122
123    /// Check if this value is `int`.
124    #[inline]
125    pub fn is_int(&self) -> bool {
126        self.tag() == JsTag::Int
127    }
128
129    /// Check if this value is `BigInt`.
130    #[inline]
131    #[cfg(feature = "bigint")]
132    pub fn is_bigint(&self) -> bool {
133        self.tag() == JsTag::BigInt || self.tag() == JsTag::ShortBigInt
134    }
135
136    /// Check if this value is `BigInt`, but short enough to fit in a i32
137    #[inline]
138    #[cfg(feature = "bigint")]
139    pub fn is_short_bigint(&self) -> bool {
140        self.tag() == JsTag::ShortBigInt
141    }
142
143    /// Check if this value is `float`.
144    #[inline]
145    pub fn is_float(&self) -> bool {
146        self.tag() == JsTag::Float64
147    }
148
149    /// Check if this value is a Javascript exception.
150    #[inline]
151    pub fn is_exception(&self) -> bool {
152        self.tag() == JsTag::Exception
153    }
154
155    /// Check if this value is a Javascript object.
156    #[inline]
157    pub fn is_object(&self) -> bool {
158        self.tag() == JsTag::Object
159    }
160
161    /// Check if this value is a Javascript array.
162    #[inline]
163    pub fn is_array(&self) -> bool {
164        unsafe { q::JS_IsArray(self.value) }
165    }
166
167    /// Check if this value is a Javascript Proxy object.
168    #[inline]
169    pub fn is_proxy(&self) -> bool {
170        unsafe { q::JS_IsProxy(self.value) }
171    }
172
173    /// Check if this value is a Javascript function.
174    #[inline]
175    pub fn is_function(&self) -> bool {
176        unsafe { q::JS_IsFunction(self.context, self.value) }
177    }
178
179    /// Check if this value is a Javascript promise.
180    #[inline]
181    pub fn is_promise(&self) -> bool {
182        unsafe { q::JS_Ext_IsPromise(self.context, self.value) }
183    }
184
185    /// Check if this value is a Javascript module.
186    #[inline]
187    pub fn is_module(&self) -> bool {
188        self.tag().is_module()
189    }
190
191    /// Check if this value is a Javascript string.
192    #[inline]
193    pub fn is_string(&self) -> bool {
194        self.tag() == JsTag::String
195    }
196
197    /// Check if this value is a bytecode compiled function.
198    #[inline]
199    pub fn is_compiled_function(&self) -> bool {
200        self.tag() == JsTag::FunctionBytecode
201    }
202
203    #[inline]
204    fn check_tag(&self, expected: JsTag) -> Result<(), ValueError> {
205        if self.tag() == expected {
206            Ok(())
207        } else {
208            Err(ValueError::UnexpectedType)
209        }
210    }
211
212    /// Convert this value into a bool
213    pub fn to_bool(&self) -> Result<bool, ValueError> {
214        self.check_tag(JsTag::Bool)?;
215        let val = unsafe { q::JS_Ext_GetBool(self.value) };
216        Ok(val == 1)
217    }
218
219    /// Convert this value into an i32
220    pub fn to_int(&self) -> Result<i32, ValueError> {
221        self.check_tag(JsTag::Int)?;
222        let val = unsafe { q::JS_Ext_GetInt(self.value) };
223        Ok(val)
224    }
225
226    /// Convert this value into an f64
227    pub fn to_float(&self) -> Result<f64, ValueError> {
228        self.check_tag(JsTag::Float64)?;
229        let val = unsafe { q::JS_Ext_GetFloat64(self.value) };
230        Ok(val)
231    }
232
233    /// Convert this value into a string
234    pub fn to_string(&self) -> Result<String, ValueError> {
235        self.check_tag(JsTag::String)?;
236        let ptr =
237            unsafe { q::JS_ToCStringLen2(self.context, std::ptr::null_mut(), self.value, false) };
238
239        if ptr.is_null() {
240            return Err(ValueError::Internal(
241                "Could not convert string: got a null pointer".into(),
242            ));
243        }
244
245        let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
246
247        let s = cstr
248            .to_str()
249            .map_err(ValueError::InvalidString)?
250            .to_string();
251
252        // Free the c string.
253        unsafe { q::JS_FreeCString(self.context, ptr) };
254
255        Ok(s)
256    }
257
258    pub fn to_array(&self) -> Result<OwnedJsArray, ValueError> {
259        OwnedJsArray::try_from_value(self.clone())
260    }
261
262    pub fn get_proxy_target(&self, recursive: bool) -> Result<OwnedJsValue, ValueError> {
263        if !self.is_proxy() {
264            return Err(ValueError::UnexpectedType);
265        }
266
267        let target = unsafe { q::JS_GetProxyTarget(self.context, self.value) };
268        let target = OwnedJsValue::new(self.context, target);
269
270        if recursive && target.is_proxy() {
271            target.get_proxy_target(true)
272        } else {
273            Ok(target)
274        }
275    }
276
277    /// Try convert this value into a object
278    pub fn try_into_object(self) -> Result<OwnedJsObject, ValueError> {
279        OwnedJsObject::try_from_value(self)
280    }
281
282    #[cfg(feature = "chrono")]
283    pub fn to_date(&self) -> Result<chrono::DateTime<chrono::Utc>, ValueError> {
284        use chrono::offset::TimeZone;
285
286        use crate::utils::js_date_constructor;
287
288        let date_constructor = js_date_constructor(self.context);
289        let is_date = unsafe { q::JS_IsInstanceOf(self.context, self.value, date_constructor) > 0 };
290
291        if is_date {
292            let getter = unsafe {
293                q::JS_GetPropertyStr(
294                    self.context,
295                    self.value,
296                    std::ffi::CStr::from_bytes_with_nul(b"getTime\0")
297                        .unwrap()
298                        .as_ptr(),
299                )
300            };
301            let tag = unsafe { q::JS_Ext_ValueGetTag(getter) };
302            assert_eq!(tag, q::JS_TAG_OBJECT);
303
304            let timestamp_raw =
305                unsafe { q::JS_Call(self.context, getter, self.value, 0, std::ptr::null_mut()) };
306
307            unsafe {
308                q::JS_FreeValue(self.context, getter);
309                q::JS_FreeValue(self.context, date_constructor);
310            };
311
312            let tag = unsafe { q::JS_Ext_ValueGetTag(timestamp_raw) };
313            if tag == q::JS_TAG_FLOAT64 {
314                let f = unsafe { q::JS_Ext_GetFloat64(timestamp_raw) } as i64;
315                let datetime = chrono::Utc.timestamp_millis_opt(f).unwrap();
316                Ok(datetime)
317            } else if tag == q::JS_TAG_INT {
318                let f = unsafe { q::JS_Ext_GetInt(timestamp_raw) } as i64;
319                let datetime = chrono::Utc.timestamp_millis_opt(f).unwrap();
320                Ok(datetime)
321            } else {
322                Err(ValueError::Internal(
323                    "Could not convert 'Date' instance to timestamp".into(),
324                ))
325            }
326        } else {
327            unsafe { q::JS_FreeValue(self.context, date_constructor) };
328            Err(ValueError::UnexpectedType)
329        }
330    }
331
332    #[cfg(feature = "bigint")]
333    pub fn to_bigint(&self) -> Result<crate::BigInt, ValueError> {
334        use crate::value::BigInt;
335        use crate::value::BigIntOrI64;
336
337        if self.is_int() {
338            let int = self.to_int()?;
339            return Ok(BigInt {
340                inner: BigIntOrI64::Int(int as i64),
341            });
342        }
343
344        // numbers between 2^53 -1 and i64::MAX is treated as float in quickjs
345        if self.is_float() {
346            let float = self.to_float()?;
347            return Ok(BigInt {
348                inner: BigIntOrI64::Int(float as i64),
349            });
350        }
351
352        if self.is_short_bigint() {
353            let int = unsafe { q::JS_Ext_GetShortBigInt(self.value) };
354            return Ok(BigInt {
355                inner: BigIntOrI64::Int(int as i64),
356            });
357        }
358
359        let ret = unsafe { q::JS_Ext_BigIntToString1(self.context, self.value, 16) };
360        let ret = OwnedJsValue::new(self.context, ret);
361
362        if ret.is_exception() {
363            let err = OwnedJsValue::new(self.context, unsafe { q::JS_GetException(self.context) });
364
365            return Err(ValueError::Internal(format!(
366                "Could not convert BigInt to string: {}",
367                err.js_to_string().unwrap()
368            )));
369        }
370
371        if !ret.is_string() {
372            return Err(ValueError::Internal(
373                "Could not convert BigInt: unexpected error".into(),
374            ));
375        }
376
377        let ret_str = ret.to_string().unwrap();
378
379        let bigint = num_bigint::BigInt::parse_bytes(ret_str.as_bytes(), 16).unwrap();
380
381        Ok(BigInt {
382            inner: BigIntOrI64::BigInt(bigint),
383        })
384        // }
385    }
386
387    /// Try convert this value into a function
388    pub fn try_into_function(self) -> Result<JsFunction, ValueError> {
389        JsFunction::try_from_value(self)
390    }
391
392    /// Try convert this value into a function
393    pub fn try_into_promise(self) -> Result<OwnedJsPromise, ValueError> {
394        OwnedJsPromise::try_from_value(self)
395    }
396
397    /// Try convert this value into a compiled function
398    pub fn try_into_compiled_function(self) -> Result<JsCompiledFunction, ValueError> {
399        JsCompiledFunction::try_from_value(self)
400    }
401
402    /// Try convert this value into a module
403    pub fn try_into_module(self) -> Result<JsModule, ValueError> {
404        JsModule::try_from_value(self)
405    }
406
407    /// Call the Javascript `.toString()` method on this value.
408    pub fn js_to_string(&self) -> Result<String, ExecutionError> {
409        let value = if self.is_string() {
410            self.to_string()?
411        } else {
412            let raw = unsafe { q::JS_ToString(self.context, self.value) };
413            let value = OwnedJsValue::new(self.context, raw);
414
415            if !value.is_string() {
416                return Err(ExecutionError::Internal(
417                    "Could not convert value to string".into(),
418                ));
419            }
420            value.to_string()?
421        };
422
423        Ok(value)
424    }
425
426    /// Call the Javascript `JSON.stringify()` method on this value.
427    pub fn to_json_string(&self, space: u8) -> Result<String, ExecutionError> {
428        let replacer = unsafe { q::JS_Ext_NewSpecialValue(q::JS_TAG_NULL, 0) };
429        let space = unsafe { q::JS_Ext_NewInt32(self.context, space as i32) };
430        let raw = unsafe { q::JS_JSONStringify(self.context, self.value, replacer, space) };
431
432        let value = OwnedJsValue::new(self.context, raw);
433
434        unsafe {
435            q::JS_FreeValue(self.context, replacer);
436            q::JS_FreeValue(self.context, space);
437        }
438
439        if !value.is_string() {
440            return Err(ExecutionError::Internal(
441                "Could not convert value to string".to_string(),
442            ));
443        }
444
445        let value = value.to_string()?;
446
447        Ok(value)
448    }
449
450    #[cfg(test)]
451    pub(crate) fn get_ref_count(&self) -> i32 {
452        unsafe { q::JS_Ext_GetRefCount(self.value) }
453    }
454}
455
456impl Drop for OwnedJsValue {
457    fn drop(&mut self) {
458        unsafe {
459            q::JS_FreeValue(self.context, self.value);
460        }
461    }
462}
463
464impl Clone for OwnedJsValue {
465    fn clone(&self) -> Self {
466        unsafe { q::JS_DupValue(self.context, self.value) };
467        Self {
468            context: self.context,
469            value: self.value,
470        }
471    }
472}
473
474impl std::fmt::Debug for OwnedJsValue {
475    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
476        write!(f, "{:?}(_)", self.tag())
477    }
478}
479
480impl TryFrom<OwnedJsValue> for bool {
481    type Error = ValueError;
482
483    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
484        value.to_bool()
485    }
486}
487
488impl TryFrom<OwnedJsValue> for i32 {
489    type Error = ValueError;
490
491    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
492        if value.is_int() {
493            return value.to_int();
494        } else if value.is_float() {
495            let f = value.to_float()?;
496            if f.fract() != 0.0 {
497                return Err(ValueError::UnexpectedType);
498            }
499            if f < (i32::MIN as f64) || f > (i32::MAX as f64) {
500                return Err(ValueError::OutOfRange);
501            }
502            return Ok(f as i32);
503        }
504        Err(ValueError::UnexpectedType)
505    }
506}
507
508impl TryFrom<OwnedJsValue> for f64 {
509    type Error = ValueError;
510
511    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
512        if value.is_float() {
513            return value.to_float();
514        } else if value.is_int() {
515            let i = value.to_int()?;
516            return Ok(i as f64);
517        }
518        Err(ValueError::UnexpectedType)
519    }
520}
521
522impl TryFrom<OwnedJsValue> for String {
523    type Error = ValueError;
524
525    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
526        value.to_string()
527    }
528}
529
530#[cfg(feature = "chrono")]
531impl TryFrom<OwnedJsValue> for DateTime<Utc> {
532    type Error = ValueError;
533
534    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
535        value.to_date()
536    }
537}
538
539#[cfg(feature = "bigint")]
540impl TryFrom<OwnedJsValue> for crate::BigInt {
541    type Error = ValueError;
542
543    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
544        value.to_bigint()
545    }
546}
547
548#[cfg(feature = "bigint")]
549impl TryFrom<OwnedJsValue> for i64 {
550    type Error = ValueError;
551
552    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
553        if value.is_int() {
554            value.to_int().map(|v| v as i64)
555        } else {
556            value
557                .to_bigint()
558                .and_then(|v| v.as_i64().ok_or(ValueError::BigIntOverflow))
559        }
560    }
561}
562
563#[cfg(feature = "bigint")]
564impl TryFrom<OwnedJsValue> for u64 {
565    type Error = ValueError;
566
567    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
568        use num_traits::ToPrimitive;
569        let bigint = value.to_bigint()?;
570        bigint
571            .into_bigint()
572            .to_u64()
573            .ok_or(ValueError::BigIntOverflow)
574    }
575}
576
577#[cfg(feature = "bigint")]
578impl TryFrom<OwnedJsValue> for i128 {
579    type Error = ValueError;
580
581    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
582        use num_traits::ToPrimitive;
583        let bigint = value.to_bigint()?;
584        bigint
585            .into_bigint()
586            .to_i128()
587            .ok_or(ValueError::BigIntOverflow)
588    }
589}
590
591#[cfg(feature = "bigint")]
592impl TryFrom<OwnedJsValue> for u128 {
593    type Error = ValueError;
594
595    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
596        use num_traits::ToPrimitive;
597        let bigint = value.to_bigint()?;
598        bigint
599            .into_bigint()
600            .to_u128()
601            .ok_or(ValueError::BigIntOverflow)
602    }
603}
604
605#[cfg(feature = "bigint")]
606impl TryFrom<OwnedJsValue> for num_bigint::BigInt {
607    type Error = ValueError;
608
609    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
610        value.to_bigint().map(|v| v.into_bigint())
611    }
612}
613
614impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Option<T> {
615    type Error = ValueError;
616
617    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
618        if value.is_null() {
619            return Ok(None);
620        }
621        Ok(Some(value.try_into()?))
622    }
623}
624
625impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Vec<T> {
626    type Error = ValueError;
627
628    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
629        let arr = value.to_array()?;
630        let mut ret: Vec<T> = vec![];
631        for i in 0..arr.length() {
632            let item = arr.get_index(i as u32).unwrap();
633            if let Some(item) = item {
634                let item = item.try_into()?;
635                ret.push(item);
636            }
637        }
638        Ok(ret)
639    }
640}
641
642impl<K: From<String> + PartialEq + Eq + Hash, V: TryFrom<OwnedJsValue, Error = ValueError>>
643    TryFrom<OwnedJsValue> for HashMap<K, V>
644{
645    type Error = ValueError;
646
647    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
648        let obj = value.try_into_object()?;
649        let mut ret: HashMap<K, V> = HashMap::new();
650        let mut iter = obj.properties_iter()?.step_by(2);
651        while let Some(Ok(key)) = iter.next() {
652            let key = key.to_string()?;
653            let item = obj.property(&key).unwrap();
654            if let Some(item) = item {
655                let item = item.try_into()?;
656                ret.insert(key.into(), item);
657            }
658        }
659        Ok(ret)
660    }
661}
662
663impl TryFrom<OwnedJsValue> for JsFunction {
664    type Error = ValueError;
665
666    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
667        JsFunction::try_from_value(value)
668    }
669}
670
671impl TryFrom<OwnedJsValue> for OwnedJsPromise {
672    type Error = ValueError;
673
674    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
675        OwnedJsPromise::try_from_value(value)
676    }
677}
678
679impl TryFrom<OwnedJsValue> for OwnedJsArray {
680    type Error = ValueError;
681
682    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
683        OwnedJsArray::try_from_value(value)
684    }
685}
686
687impl TryFrom<OwnedJsValue> for OwnedJsObject {
688    type Error = ValueError;
689
690    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
691        OwnedJsObject::try_from_value(value)
692    }
693}
694
695impl TryFrom<OwnedJsValue> for JsCompiledFunction {
696    type Error = ValueError;
697
698    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
699        JsCompiledFunction::try_from_value(value)
700    }
701}
702
703impl TryFrom<OwnedJsValue> for JsModule {
704    type Error = ValueError;
705
706    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
707        JsModule::try_from_value(value)
708    }
709}
710
711/// to avoid infinite recursion, we need to implement a ToOwnedJsValue trait for T,
712/// and then implement the `From<(*mut q::JSContext, T)>` trait for T and XXX<T> where T: ToOwnedJsValue
713///
714/// This trait should not be public, use the `From<(*mut q::JSContext, T)>` trait outside of this module.
715pub trait ToOwnedJsValue {
716    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue;
717}
718
719impl ToOwnedJsValue for bool {
720    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
721        let val = create_bool(context, self);
722        OwnedJsValue::new(context, val)
723    }
724}
725
726impl ToOwnedJsValue for i32 {
727    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
728        let val = create_int(context, self);
729        OwnedJsValue::new(context, val)
730    }
731}
732
733impl ToOwnedJsValue for i8 {
734    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
735        let val = create_int(context, self as i32);
736        OwnedJsValue::new(context, val)
737    }
738}
739
740impl ToOwnedJsValue for i16 {
741    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
742        let val = create_int(context, self as i32);
743        OwnedJsValue::new(context, val)
744    }
745}
746
747impl ToOwnedJsValue for u8 {
748    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
749        let val = create_int(context, self as i32);
750        OwnedJsValue::new(context, val)
751    }
752}
753
754impl ToOwnedJsValue for u16 {
755    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
756        let val = create_int(context, self as i32);
757        OwnedJsValue::new(context, val)
758    }
759}
760
761impl ToOwnedJsValue for f64 {
762    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
763        let val = create_float(context, self);
764        OwnedJsValue::new(context, val)
765    }
766}
767
768impl ToOwnedJsValue for u32 {
769    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
770        let val = create_float(context, self as f64);
771        OwnedJsValue::new(context, val)
772    }
773}
774
775impl ToOwnedJsValue for &str {
776    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
777        let val = create_string(context, self).unwrap();
778        OwnedJsValue::new(context, val)
779    }
780}
781
782impl ToOwnedJsValue for String {
783    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
784        let val = create_string(context, &self).unwrap();
785        OwnedJsValue::new(context, val)
786    }
787}
788
789#[cfg(feature = "chrono")]
790impl ToOwnedJsValue for DateTime<Utc> {
791    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
792        let val = create_date(context, self).unwrap();
793        OwnedJsValue::new(context, val)
794    }
795}
796
797#[cfg(feature = "bigint")]
798impl ToOwnedJsValue for crate::BigInt {
799    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
800        let val = create_bigint(context, self).unwrap();
801        OwnedJsValue::new(context, val)
802    }
803}
804
805#[cfg(feature = "bigint")]
806impl ToOwnedJsValue for num_bigint::BigInt {
807    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
808        let val = create_bigint(context, self.into()).unwrap();
809        OwnedJsValue::new(context, val)
810    }
811}
812
813#[cfg(feature = "bigint")]
814impl ToOwnedJsValue for i64 {
815    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
816        let val = create_bigint(context, self.into()).unwrap();
817        OwnedJsValue::new(context, val)
818    }
819}
820
821#[cfg(feature = "bigint")]
822impl ToOwnedJsValue for u64 {
823    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
824        let bigint: num_bigint::BigInt = self.into();
825        let val = create_bigint(context, bigint.into()).unwrap();
826        OwnedJsValue::new(context, val)
827    }
828}
829
830#[cfg(feature = "bigint")]
831impl ToOwnedJsValue for i128 {
832    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
833        let bigint: num_bigint::BigInt = self.into();
834        let val = create_bigint(context, bigint.into()).unwrap();
835        OwnedJsValue::new(context, val)
836    }
837}
838
839#[cfg(feature = "bigint")]
840impl ToOwnedJsValue for u128 {
841    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
842        let bigint: num_bigint::BigInt = self.into();
843        let val = create_bigint(context, bigint.into()).unwrap();
844        OwnedJsValue::new(context, val)
845    }
846}
847
848impl ToOwnedJsValue for JsFunction {
849    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
850        let val = create_function(context, self).unwrap();
851        OwnedJsValue::new(context, val)
852    }
853}
854
855impl ToOwnedJsValue for OwnedJsPromise {
856    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
857        let val = unsafe { self.into_value().extract() };
858        OwnedJsValue::new(context, val)
859    }
860}
861
862/// for some cases like HashMap<String, OwnedJsValue>
863impl ToOwnedJsValue for OwnedJsValue {
864    fn to_owned(self, _: *mut q::JSContext) -> OwnedJsValue {
865        self
866    }
867}
868
869impl<T> ToOwnedJsValue for Vec<T>
870where
871    T: ToOwnedJsValue,
872{
873    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
874        let arr = create_empty_array(context).unwrap();
875        self.into_iter().enumerate().for_each(|(idx, val)| {
876            let val: OwnedJsValue = (context, val).into();
877            add_array_element(context, arr, idx as u32, unsafe { val.extract() }).unwrap();
878        });
879
880        OwnedJsValue::new(context, arr)
881    }
882}
883
884impl<K, V> ToOwnedJsValue for HashMap<K, V>
885where
886    K: Into<String>,
887    V: ToOwnedJsValue,
888{
889    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
890        let obj = create_empty_object(context).unwrap();
891        self.into_iter().for_each(|(key, val)| {
892            let val: OwnedJsValue = (context, val).into();
893            add_object_property(context, obj, key.into().as_str(), unsafe { val.extract() })
894                .unwrap();
895        });
896
897        OwnedJsValue::new(context, obj)
898    }
899}
900
901impl<T> ToOwnedJsValue for Option<T>
902where
903    T: ToOwnedJsValue,
904{
905    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
906        if let Some(val) = self {
907            (context, val).into()
908        } else {
909            OwnedJsValue::new(context, create_null())
910        }
911    }
912}
913
914impl<T> ToOwnedJsValue for &T
915where
916    T: ToOwnedJsValue,
917{
918    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
919        (context, self).into()
920    }
921}
922
923impl<T> From<(*mut q::JSContext, T)> for OwnedJsValue
924where
925    T: ToOwnedJsValue,
926{
927    fn from((context, value): (*mut q::JSContext, T)) -> Self {
928        value.to_owned(context)
929    }
930}