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        value.to_int()
493    }
494}
495
496impl TryFrom<OwnedJsValue> for f64 {
497    type Error = ValueError;
498
499    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
500        value.to_float()
501    }
502}
503
504impl TryFrom<OwnedJsValue> for String {
505    type Error = ValueError;
506
507    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
508        value.to_string()
509    }
510}
511
512#[cfg(feature = "chrono")]
513impl TryFrom<OwnedJsValue> for DateTime<Utc> {
514    type Error = ValueError;
515
516    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
517        value.to_date()
518    }
519}
520
521#[cfg(feature = "bigint")]
522impl TryFrom<OwnedJsValue> for crate::BigInt {
523    type Error = ValueError;
524
525    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
526        value.to_bigint()
527    }
528}
529
530#[cfg(feature = "bigint")]
531impl TryFrom<OwnedJsValue> for i64 {
532    type Error = ValueError;
533
534    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
535        if value.is_int() {
536            value.to_int().map(|v| v as i64)
537        } else {
538            value
539                .to_bigint()
540                .and_then(|v| v.as_i64().ok_or(ValueError::BigIntOverflow))
541        }
542    }
543}
544
545#[cfg(feature = "bigint")]
546impl TryFrom<OwnedJsValue> for u64 {
547    type Error = ValueError;
548
549    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
550        use num_traits::ToPrimitive;
551        let bigint = value.to_bigint()?;
552        bigint
553            .into_bigint()
554            .to_u64()
555            .ok_or(ValueError::BigIntOverflow)
556    }
557}
558
559#[cfg(feature = "bigint")]
560impl TryFrom<OwnedJsValue> for i128 {
561    type Error = ValueError;
562
563    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
564        use num_traits::ToPrimitive;
565        let bigint = value.to_bigint()?;
566        bigint
567            .into_bigint()
568            .to_i128()
569            .ok_or(ValueError::BigIntOverflow)
570    }
571}
572
573#[cfg(feature = "bigint")]
574impl TryFrom<OwnedJsValue> for u128 {
575    type Error = ValueError;
576
577    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
578        use num_traits::ToPrimitive;
579        let bigint = value.to_bigint()?;
580        bigint
581            .into_bigint()
582            .to_u128()
583            .ok_or(ValueError::BigIntOverflow)
584    }
585}
586
587#[cfg(feature = "bigint")]
588impl TryFrom<OwnedJsValue> for num_bigint::BigInt {
589    type Error = ValueError;
590
591    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
592        value.to_bigint().map(|v| v.into_bigint())
593    }
594}
595
596impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Option<T> {
597    type Error = ValueError;
598
599    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
600        if value.is_null() {
601            return Ok(None);
602        }
603        Ok(Some(value.try_into()?))
604    }
605}
606
607impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Vec<T> {
608    type Error = ValueError;
609
610    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
611        let arr = value.to_array()?;
612        let mut ret: Vec<T> = vec![];
613        for i in 0..arr.length() {
614            let item = arr.get_index(i as u32).unwrap();
615            if let Some(item) = item {
616                let item = item.try_into()?;
617                ret.push(item);
618            }
619        }
620        Ok(ret)
621    }
622}
623
624impl<K: From<String> + PartialEq + Eq + Hash, V: TryFrom<OwnedJsValue, Error = ValueError>>
625    TryFrom<OwnedJsValue> for HashMap<K, V>
626{
627    type Error = ValueError;
628
629    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
630        let obj = value.try_into_object()?;
631        let mut ret: HashMap<K, V> = HashMap::new();
632        let mut iter = obj.properties_iter()?.step_by(2);
633        while let Some(Ok(key)) = iter.next() {
634            let key = key.to_string()?;
635            let item = obj.property(&key).unwrap();
636            if let Some(item) = item {
637                let item = item.try_into()?;
638                ret.insert(key.into(), item);
639            }
640        }
641        Ok(ret)
642    }
643}
644
645impl TryFrom<OwnedJsValue> for JsFunction {
646    type Error = ValueError;
647
648    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
649        JsFunction::try_from_value(value)
650    }
651}
652
653impl TryFrom<OwnedJsValue> for OwnedJsPromise {
654    type Error = ValueError;
655
656    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
657        OwnedJsPromise::try_from_value(value)
658    }
659}
660
661impl TryFrom<OwnedJsValue> for OwnedJsArray {
662    type Error = ValueError;
663
664    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
665        OwnedJsArray::try_from_value(value)
666    }
667}
668
669impl TryFrom<OwnedJsValue> for OwnedJsObject {
670    type Error = ValueError;
671
672    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
673        OwnedJsObject::try_from_value(value)
674    }
675}
676
677impl TryFrom<OwnedJsValue> for JsCompiledFunction {
678    type Error = ValueError;
679
680    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
681        JsCompiledFunction::try_from_value(value)
682    }
683}
684
685impl TryFrom<OwnedJsValue> for JsModule {
686    type Error = ValueError;
687
688    fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
689        JsModule::try_from_value(value)
690    }
691}
692
693/// to avoid infinite recursion, we need to implement a ToOwnedJsValue trait for T,
694/// and then implement the `From<(*mut q::JSContext, T)>` trait for T and XXX<T> where T: ToOwnedJsValue
695///
696/// This trait should not be public, use the `From<(*mut q::JSContext, T)>` trait outside of this module.
697pub trait ToOwnedJsValue {
698    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue;
699}
700
701impl ToOwnedJsValue for bool {
702    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
703        let val = create_bool(context, self);
704        OwnedJsValue::new(context, val)
705    }
706}
707
708impl ToOwnedJsValue for i32 {
709    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
710        let val = create_int(context, self);
711        OwnedJsValue::new(context, val)
712    }
713}
714
715impl ToOwnedJsValue for i8 {
716    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
717        let val = create_int(context, self as i32);
718        OwnedJsValue::new(context, val)
719    }
720}
721
722impl ToOwnedJsValue for i16 {
723    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
724        let val = create_int(context, self as i32);
725        OwnedJsValue::new(context, val)
726    }
727}
728
729impl ToOwnedJsValue for u8 {
730    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
731        let val = create_int(context, self as i32);
732        OwnedJsValue::new(context, val)
733    }
734}
735
736impl ToOwnedJsValue for u16 {
737    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
738        let val = create_int(context, self as i32);
739        OwnedJsValue::new(context, val)
740    }
741}
742
743impl ToOwnedJsValue for f64 {
744    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
745        let val = create_float(context, self);
746        OwnedJsValue::new(context, val)
747    }
748}
749
750impl ToOwnedJsValue for u32 {
751    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
752        let val = create_float(context, self as f64);
753        OwnedJsValue::new(context, val)
754    }
755}
756
757impl ToOwnedJsValue for &str {
758    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
759        let val = create_string(context, self).unwrap();
760        OwnedJsValue::new(context, val)
761    }
762}
763
764impl ToOwnedJsValue for String {
765    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
766        let val = create_string(context, &self).unwrap();
767        OwnedJsValue::new(context, val)
768    }
769}
770
771#[cfg(feature = "chrono")]
772impl ToOwnedJsValue for DateTime<Utc> {
773    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
774        let val = create_date(context, self).unwrap();
775        OwnedJsValue::new(context, val)
776    }
777}
778
779#[cfg(feature = "bigint")]
780impl ToOwnedJsValue for crate::BigInt {
781    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
782        let val = create_bigint(context, self).unwrap();
783        OwnedJsValue::new(context, val)
784    }
785}
786
787#[cfg(feature = "bigint")]
788impl ToOwnedJsValue for num_bigint::BigInt {
789    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
790        let val = create_bigint(context, self.into()).unwrap();
791        OwnedJsValue::new(context, val)
792    }
793}
794
795#[cfg(feature = "bigint")]
796impl ToOwnedJsValue for i64 {
797    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
798        let val = create_bigint(context, self.into()).unwrap();
799        OwnedJsValue::new(context, val)
800    }
801}
802
803#[cfg(feature = "bigint")]
804impl ToOwnedJsValue for u64 {
805    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
806        let bigint: num_bigint::BigInt = self.into();
807        let val = create_bigint(context, bigint.into()).unwrap();
808        OwnedJsValue::new(context, val)
809    }
810}
811
812#[cfg(feature = "bigint")]
813impl ToOwnedJsValue for i128 {
814    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
815        let bigint: num_bigint::BigInt = self.into();
816        let val = create_bigint(context, bigint.into()).unwrap();
817        OwnedJsValue::new(context, val)
818    }
819}
820
821#[cfg(feature = "bigint")]
822impl ToOwnedJsValue for u128 {
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
830impl ToOwnedJsValue for JsFunction {
831    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
832        let val = create_function(context, self).unwrap();
833        OwnedJsValue::new(context, val)
834    }
835}
836
837impl ToOwnedJsValue for OwnedJsPromise {
838    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
839        let val = unsafe { self.into_value().extract() };
840        OwnedJsValue::new(context, val)
841    }
842}
843
844/// for some cases like HashMap<String, OwnedJsValue>
845impl ToOwnedJsValue for OwnedJsValue {
846    fn to_owned(self, _: *mut q::JSContext) -> OwnedJsValue {
847        self
848    }
849}
850
851impl<T> ToOwnedJsValue for Vec<T>
852where
853    T: ToOwnedJsValue,
854{
855    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
856        let arr = create_empty_array(context).unwrap();
857        self.into_iter().enumerate().for_each(|(idx, val)| {
858            let val: OwnedJsValue = (context, val).into();
859            add_array_element(context, arr, idx as u32, unsafe { val.extract() }).unwrap();
860        });
861
862        OwnedJsValue::new(context, arr)
863    }
864}
865
866impl<K, V> ToOwnedJsValue for HashMap<K, V>
867where
868    K: Into<String>,
869    V: ToOwnedJsValue,
870{
871    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
872        let obj = create_empty_object(context).unwrap();
873        self.into_iter().for_each(|(key, val)| {
874            let val: OwnedJsValue = (context, val).into();
875            add_object_property(context, obj, key.into().as_str(), unsafe { val.extract() })
876                .unwrap();
877        });
878
879        OwnedJsValue::new(context, obj)
880    }
881}
882
883impl<T> ToOwnedJsValue for Option<T>
884where
885    T: ToOwnedJsValue,
886{
887    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
888        if let Some(val) = self {
889            (context, val).into()
890        } else {
891            OwnedJsValue::new(context, create_null())
892        }
893    }
894}
895
896impl<T> ToOwnedJsValue for &T
897where
898    T: ToOwnedJsValue,
899{
900    fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
901        (context, self).into()
902    }
903}
904
905impl<T> From<(*mut q::JSContext, T)> for OwnedJsValue
906where
907    T: ToOwnedJsValue,
908{
909    fn from((context, value): (*mut q::JSContext, T)) -> Self {
910        value.to_owned(context)
911    }
912}