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_promise(&self) -> bool {
188 unsafe { q::JS_Ext_IsPromise(self.context, self.value) }
189 }
190
191 #[inline]
193 pub fn is_module(&self) -> bool {
194 self.tag().is_module()
195 }
196
197 #[inline]
199 pub fn is_string(&self) -> bool {
200 self.tag() == JsTag::String
201 }
202
203 #[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 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 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 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 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 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 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 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 }
392
393 pub fn try_into_function(self) -> Result<JsFunction, ValueError> {
395 JsFunction::try_from_value(self)
396 }
397
398 pub fn try_into_promise(self) -> Result<OwnedJsPromise, ValueError> {
400 OwnedJsPromise::try_from_value(self)
401 }
402
403 pub fn try_into_compiled_function(self) -> Result<JsCompiledFunction, ValueError> {
405 JsCompiledFunction::try_from_value(self)
406 }
407
408 pub fn try_into_module(self) -> Result<JsModule, ValueError> {
410 JsModule::try_from_value(self)
411 }
412
413 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 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
717pub 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
868impl 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}