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