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