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