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