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_float() {
325 let float = self.to_float()?;
326 return Ok(BigInt {
327 inner: BigIntOrI64::Int(float as i64),
328 });
329 }
330
331 if self.is_short_bigint() {
332 let int = unsafe { q::JS_Ext_GetShortBigInt(self.value) };
333 return Ok(BigInt {
334 inner: BigIntOrI64::Int(int as i64),
335 });
336 }
337
338 let ret = unsafe { q::JS_Ext_BigIntToString1(self.context, self.value, 16) };
339 let ret = OwnedJsValue::new(self.context, ret);
340
341 if ret.is_exception() {
342 let err = OwnedJsValue::new(self.context, unsafe { q::JS_GetException(self.context) });
343
344 return Err(ValueError::Internal(format!(
345 "Could not convert BigInt to string: {}",
346 err.js_to_string().unwrap()
347 )));
348 }
349
350 if !ret.is_string() {
351 return Err(ValueError::Internal(
352 "Could not convert BigInt: unexpected error".into(),
353 ));
354 }
355
356 let ret_str = ret.to_string().unwrap();
357
358 let bigint = num_bigint::BigInt::parse_bytes(ret_str.as_bytes(), 16).unwrap();
359
360 Ok(BigInt {
361 inner: BigIntOrI64::BigInt(bigint),
362 })
363 }
365
366 pub fn try_into_function(self) -> Result<JsFunction, ValueError> {
368 JsFunction::try_from_value(self)
369 }
370
371 pub fn try_into_promise(self) -> Result<OwnedJsPromise, ValueError> {
373 OwnedJsPromise::try_from_value(self)
374 }
375
376 pub fn try_into_compiled_function(self) -> Result<JsCompiledFunction, ValueError> {
378 JsCompiledFunction::try_from_value(self)
379 }
380
381 pub fn try_into_module(self) -> Result<JsModule, ValueError> {
383 JsModule::try_from_value(self)
384 }
385
386 pub fn js_to_string(&self) -> Result<String, ExecutionError> {
388 let value = if self.is_string() {
389 self.to_string()?
390 } else {
391 let raw = unsafe { q::JS_ToString(self.context, self.value) };
392 let value = OwnedJsValue::new(self.context, raw);
393
394 if !value.is_string() {
395 return Err(ExecutionError::Internal(
396 "Could not convert value to string".into(),
397 ));
398 }
399 value.to_string()?
400 };
401
402 Ok(value)
403 }
404
405 pub fn to_json_string(&self, space: u8) -> Result<String, ExecutionError> {
407 let replacer = unsafe { q::JS_Ext_NewSpecialValue(q::JS_TAG_NULL, 0) };
408 let space = unsafe { q::JS_Ext_NewInt32(self.context, space as i32) };
409 let raw = unsafe { q::JS_JSONStringify(self.context, self.value, replacer, space) };
410
411 let value = OwnedJsValue::new(self.context, raw);
412
413 unsafe {
414 q::JS_FreeValue(self.context, replacer);
415 q::JS_FreeValue(self.context, space);
416 }
417
418 if !value.is_string() {
419 return Err(ExecutionError::Internal(
420 "Could not convert value to string".to_string(),
421 ));
422 }
423
424 let value = value.to_string()?;
425
426 Ok(value)
427 }
428
429 #[cfg(test)]
430 pub(crate) fn get_ref_count(&self) -> i32 {
431 unsafe { q::JS_Ext_GetRefCount(self.value) }
432 }
433}
434
435impl Drop for OwnedJsValue {
436 fn drop(&mut self) {
437 unsafe {
438 q::JS_FreeValue(self.context, self.value);
439 }
440 }
441}
442
443impl Clone for OwnedJsValue {
444 fn clone(&self) -> Self {
445 unsafe { q::JS_DupValue(self.context, self.value) };
446 Self {
447 context: self.context,
448 value: self.value,
449 }
450 }
451}
452
453impl std::fmt::Debug for OwnedJsValue {
454 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
455 write!(f, "{:?}(_)", self.tag())
456 }
457}
458
459impl TryFrom<OwnedJsValue> for bool {
460 type Error = ValueError;
461
462 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
463 value.to_bool()
464 }
465}
466
467impl TryFrom<OwnedJsValue> for i32 {
468 type Error = ValueError;
469
470 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
471 value.to_int()
472 }
473}
474
475impl TryFrom<OwnedJsValue> for f64 {
476 type Error = ValueError;
477
478 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
479 value.to_float()
480 }
481}
482
483impl TryFrom<OwnedJsValue> for String {
484 type Error = ValueError;
485
486 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
487 value.to_string()
488 }
489}
490
491#[cfg(feature = "chrono")]
492impl TryFrom<OwnedJsValue> for DateTime<Utc> {
493 type Error = ValueError;
494
495 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
496 value.to_date()
497 }
498}
499
500#[cfg(feature = "bigint")]
501impl TryFrom<OwnedJsValue> for crate::BigInt {
502 type Error = ValueError;
503
504 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
505 value.to_bigint()
506 }
507}
508
509#[cfg(feature = "bigint")]
510impl TryFrom<OwnedJsValue> for i64 {
511 type Error = ValueError;
512
513 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
514 if value.is_int() {
515 value.to_int().map(|v| v as i64)
516 } else {
517 value
518 .to_bigint()
519 .and_then(|v| v.as_i64().ok_or(ValueError::BigIntOverflow))
520 }
521 }
522}
523
524#[cfg(feature = "bigint")]
525impl TryFrom<OwnedJsValue> for u64 {
526 type Error = ValueError;
527
528 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
529 use num_traits::ToPrimitive;
530 let bigint = value.to_bigint()?;
531 bigint
532 .into_bigint()
533 .to_u64()
534 .ok_or(ValueError::BigIntOverflow)
535 }
536}
537
538#[cfg(feature = "bigint")]
539impl TryFrom<OwnedJsValue> for i128 {
540 type Error = ValueError;
541
542 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
543 use num_traits::ToPrimitive;
544 let bigint = value.to_bigint()?;
545 bigint
546 .into_bigint()
547 .to_i128()
548 .ok_or(ValueError::BigIntOverflow)
549 }
550}
551
552#[cfg(feature = "bigint")]
553impl TryFrom<OwnedJsValue> for u128 {
554 type Error = ValueError;
555
556 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
557 use num_traits::ToPrimitive;
558 let bigint = value.to_bigint()?;
559 bigint
560 .into_bigint()
561 .to_u128()
562 .ok_or(ValueError::BigIntOverflow)
563 }
564}
565
566#[cfg(feature = "bigint")]
567impl TryFrom<OwnedJsValue> for num_bigint::BigInt {
568 type Error = ValueError;
569
570 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
571 value.to_bigint().map(|v| v.into_bigint())
572 }
573}
574
575impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Option<T> {
576 type Error = ValueError;
577
578 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
579 if value.is_null() {
580 return Ok(None);
581 }
582 Ok(Some(value.try_into()?))
583 }
584}
585
586impl<T: TryFrom<OwnedJsValue, Error = ValueError>> TryFrom<OwnedJsValue> for Vec<T> {
587 type Error = ValueError;
588
589 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
590 let arr = value.to_array()?;
591 let mut ret: Vec<T> = vec![];
592 for i in 0..arr.length() {
593 let item = arr.get_index(i as u32).unwrap();
594 if let Some(item) = item {
595 let item = item.try_into()?;
596 ret.push(item);
597 }
598 }
599 Ok(ret)
600 }
601}
602
603impl<K: From<String> + PartialEq + Eq + Hash, V: TryFrom<OwnedJsValue, Error = ValueError>>
604 TryFrom<OwnedJsValue> for HashMap<K, V>
605{
606 type Error = ValueError;
607
608 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
609 let obj = value.try_into_object()?;
610 let mut ret: HashMap<K, V> = HashMap::new();
611 let mut iter = obj.properties_iter()?.step_by(2);
612 while let Some(Ok(key)) = iter.next() {
613 let key = key.to_string()?;
614 let item = obj.property(&key).unwrap();
615 if let Some(item) = item {
616 let item = item.try_into()?;
617 ret.insert(key.into(), item);
618 }
619 }
620 Ok(ret)
621 }
622}
623
624impl TryFrom<OwnedJsValue> for JsFunction {
625 type Error = ValueError;
626
627 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
628 JsFunction::try_from_value(value)
629 }
630}
631
632impl TryFrom<OwnedJsValue> for OwnedJsPromise {
633 type Error = ValueError;
634
635 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
636 OwnedJsPromise::try_from_value(value)
637 }
638}
639
640impl TryFrom<OwnedJsValue> for OwnedJsArray {
641 type Error = ValueError;
642
643 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
644 OwnedJsArray::try_from_value(value)
645 }
646}
647
648impl TryFrom<OwnedJsValue> for OwnedJsObject {
649 type Error = ValueError;
650
651 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
652 OwnedJsObject::try_from_value(value)
653 }
654}
655
656impl TryFrom<OwnedJsValue> for JsCompiledFunction {
657 type Error = ValueError;
658
659 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
660 JsCompiledFunction::try_from_value(value)
661 }
662}
663
664impl TryFrom<OwnedJsValue> for JsModule {
665 type Error = ValueError;
666
667 fn try_from(value: OwnedJsValue) -> Result<Self, Self::Error> {
668 JsModule::try_from_value(value)
669 }
670}
671
672pub trait ToOwnedJsValue {
677 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue;
678}
679
680impl ToOwnedJsValue for bool {
681 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
682 let val = create_bool(context, self);
683 OwnedJsValue::new(context, val)
684 }
685}
686
687impl ToOwnedJsValue for i32 {
688 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
689 let val = create_int(context, self);
690 OwnedJsValue::new(context, val)
691 }
692}
693
694impl ToOwnedJsValue for i8 {
695 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
696 let val = create_int(context, self as i32);
697 OwnedJsValue::new(context, val)
698 }
699}
700
701impl ToOwnedJsValue for i16 {
702 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
703 let val = create_int(context, self as i32);
704 OwnedJsValue::new(context, val)
705 }
706}
707
708impl ToOwnedJsValue for u8 {
709 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
710 let val = create_int(context, self as i32);
711 OwnedJsValue::new(context, val)
712 }
713}
714
715impl ToOwnedJsValue for u16 {
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 f64 {
723 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
724 let val = create_float(context, self);
725 OwnedJsValue::new(context, val)
726 }
727}
728
729impl ToOwnedJsValue for u32 {
730 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
731 let val = create_float(context, self as f64);
732 OwnedJsValue::new(context, val)
733 }
734}
735
736impl ToOwnedJsValue for &str {
737 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
738 let val = create_string(context, self).unwrap();
739 OwnedJsValue::new(context, val)
740 }
741}
742
743impl ToOwnedJsValue for String {
744 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
745 let val = create_string(context, &self).unwrap();
746 OwnedJsValue::new(context, val)
747 }
748}
749
750#[cfg(feature = "chrono")]
751impl ToOwnedJsValue for DateTime<Utc> {
752 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
753 let val = create_date(context, self).unwrap();
754 OwnedJsValue::new(context, val)
755 }
756}
757
758#[cfg(feature = "bigint")]
759impl ToOwnedJsValue for crate::BigInt {
760 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
761 let val = create_bigint(context, self).unwrap();
762 OwnedJsValue::new(context, val)
763 }
764}
765
766#[cfg(feature = "bigint")]
767impl ToOwnedJsValue for num_bigint::BigInt {
768 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
769 let val = create_bigint(context, self.into()).unwrap();
770 OwnedJsValue::new(context, val)
771 }
772}
773
774#[cfg(feature = "bigint")]
775impl ToOwnedJsValue for i64 {
776 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
777 let val = create_bigint(context, self.into()).unwrap();
778 OwnedJsValue::new(context, val)
779 }
780}
781
782#[cfg(feature = "bigint")]
783impl ToOwnedJsValue for u64 {
784 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
785 let bigint: num_bigint::BigInt = self.into();
786 let val = create_bigint(context, bigint.into()).unwrap();
787 OwnedJsValue::new(context, val)
788 }
789}
790
791#[cfg(feature = "bigint")]
792impl ToOwnedJsValue for i128 {
793 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
794 let bigint: num_bigint::BigInt = self.into();
795 let val = create_bigint(context, bigint.into()).unwrap();
796 OwnedJsValue::new(context, val)
797 }
798}
799
800#[cfg(feature = "bigint")]
801impl ToOwnedJsValue for u128 {
802 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
803 let bigint: num_bigint::BigInt = self.into();
804 let val = create_bigint(context, bigint.into()).unwrap();
805 OwnedJsValue::new(context, val)
806 }
807}
808
809impl ToOwnedJsValue for JsFunction {
810 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
811 let val = create_function(context, self).unwrap();
812 OwnedJsValue::new(context, val)
813 }
814}
815
816impl ToOwnedJsValue for OwnedJsPromise {
817 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
818 let val = unsafe { self.into_value().extract() };
819 OwnedJsValue::new(context, val)
820 }
821}
822
823impl ToOwnedJsValue for OwnedJsValue {
825 fn to_owned(self, _: *mut q::JSContext) -> OwnedJsValue {
826 self
827 }
828}
829
830impl<T> ToOwnedJsValue for Vec<T>
831where
832 T: ToOwnedJsValue,
833{
834 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
835 let arr = create_empty_array(context).unwrap();
836 self.into_iter().enumerate().for_each(|(idx, val)| {
837 let val: OwnedJsValue = (context, val).into();
838 add_array_element(context, arr, idx as u32, unsafe { val.extract() }).unwrap();
839 });
840
841 OwnedJsValue::new(context, arr)
842 }
843}
844
845impl<K, V> ToOwnedJsValue for HashMap<K, V>
846where
847 K: Into<String>,
848 V: ToOwnedJsValue,
849{
850 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
851 let obj = create_empty_object(context).unwrap();
852 self.into_iter().for_each(|(key, val)| {
853 let val: OwnedJsValue = (context, val).into();
854 add_object_property(context, obj, key.into().as_str(), unsafe { val.extract() })
855 .unwrap();
856 });
857
858 OwnedJsValue::new(context, obj)
859 }
860}
861
862impl<T> ToOwnedJsValue for Option<T>
863where
864 T: ToOwnedJsValue,
865{
866 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
867 if let Some(val) = self {
868 (context, val).into()
869 } else {
870 OwnedJsValue::new(context, create_null())
871 }
872 }
873}
874
875impl<T> ToOwnedJsValue for &T
876where
877 T: ToOwnedJsValue,
878{
879 fn to_owned(self, context: *mut q::JSContext) -> OwnedJsValue {
880 (context, self).into()
881 }
882}
883
884impl<T> From<(*mut q::JSContext, T)> for OwnedJsValue
885where
886 T: ToOwnedJsValue,
887{
888 fn from((context, value): (*mut q::JSContext, T)) -> Self {
889 value.to_owned(context)
890 }
891}