1use std::convert::Infallible;
4use std::mem::MaybeUninit;
5use std::ops::Deref;
6use std::ops::DerefMut;
7
8use deno_error::JsErrorBox;
9use deno_error::JsErrorClass;
10use smallvec::SmallVec;
11use v8::Local;
12use v8::PinScope;
13
14use crate::error::DataError;
15use crate::runtime::ops;
16
17pub trait ToV8<'a> {
77 type Error: JsErrorClass;
78
79 fn to_v8<'i>(
81 self,
82 scope: &mut v8::PinScope<'a, 'i>,
83 ) -> Result<v8::Local<'a, v8::Value>, Self::Error>;
84}
85
86pub trait FromV8<'a>: Sized {
124 type Error: JsErrorClass;
125
126 fn from_v8<'i>(
128 scope: &mut v8::PinScope<'a, 'i>,
129 value: v8::Local<'a, v8::Value>,
130 ) -> Result<Self, Self::Error>;
131}
132
133pub trait FromV8Scopeless<'a>: Sized + FromV8<'a> {
135 fn from_v8(value: v8::Local<'a, v8::Value>) -> Result<Self, Self::Error>;
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
142#[repr(transparent)]
144pub struct Smi<T: SmallInt>(pub T);
145
146pub trait SmallInt {
148 const NAME: &'static str;
149
150 #[allow(
151 clippy::wrong_self_convention,
152 reason = "takes self by value intentionally"
153 )]
154 fn as_i32(self) -> i32;
155 fn from_i32(value: i32) -> Self;
156}
157
158macro_rules! impl_smallint {
159 (for $($t:ty),*) => {
160 $(
161 impl SmallInt for $t {
162 const NAME: &'static str = stringify!($t);
163 #[allow(clippy::wrong_self_convention, reason = "takes self by value intentionally")]
164 #[inline(always)]
165 fn as_i32(self) -> i32 {
166 self as _
167 }
168
169 #[inline(always)]
170 fn from_i32(value: i32) -> Self {
171 value as _
172 }
173 }
174 )*
175 };
176}
177
178impl_smallint!(for u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
179
180impl<'s, T: SmallInt> ToV8<'s> for Smi<T> {
181 type Error = Infallible;
182
183 #[inline]
184 fn to_v8<'i>(
185 self,
186 scope: &mut v8::PinScope<'s, 'i>,
187 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
188 Ok(v8::Integer::new(scope, self.0.as_i32()).into())
189 }
190}
191
192impl<'s, T: SmallInt> FromV8<'s> for Smi<T> {
193 type Error = DataError;
194
195 fn from_v8<'i>(
196 _scope: &mut PinScope<'s, 'i>,
197 value: Local<'s, v8::Value>,
198 ) -> Result<Self, Self::Error> {
199 <Self as FromV8Scopeless>::from_v8(value)
200 }
201}
202
203impl<'s, T: SmallInt> FromV8Scopeless<'s> for Smi<T> {
204 #[inline]
205 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
206 let v = ops::to_i32_option(&value).ok_or_else(|| {
207 DataError(v8::DataError::BadType {
208 actual: value.type_repr(),
209 expected: T::NAME,
210 })
211 })?;
212 Ok(Smi(T::from_i32(v)))
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
217#[repr(transparent)]
219pub struct Number<T: Numeric>(pub T);
220
221pub trait Numeric: Sized {
223 const NAME: &'static str;
224 #[allow(
225 clippy::wrong_self_convention,
226 reason = "takes self by value intentionally"
227 )]
228 fn as_f64(self) -> f64;
229 fn from_value(value: &v8::Value) -> Option<Self>;
230}
231
232macro_rules! impl_numeric {
233 ($($t:ty : $from: path ),*) => {
234 $(
235 impl Numeric for $t {
236 const NAME: &'static str = stringify!($t);
237 #[inline(always)]
238 fn from_value(value: &v8::Value) -> Option<Self> {
239 $from(value).map(|v| v as _)
240 }
241
242 #[allow(clippy::wrong_self_convention, reason = "takes self by value intentionally")]
243 #[inline(always)]
244 fn as_f64(self) -> f64 {
245 self as _
246 }
247 }
248 )*
249 };
250}
251
252impl_numeric!(
253 f32 : ops::to_f32_option,
254 f64 : ops::to_f64_option,
255 u32 : ops::to_u32_option,
256 u64 : ops::to_u64_option,
257 usize : ops::to_u64_option,
258 i32 : ops::to_i32_option,
259 i64 : ops::to_i64_option,
260 isize : ops::to_i64_option
261);
262
263impl<'s, T: Numeric> ToV8<'s> for Number<T> {
264 type Error = Infallible;
265 #[inline]
266 fn to_v8<'i>(
267 self,
268 scope: &mut v8::PinScope<'s, 'i>,
269 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
270 Ok(v8::Number::new(scope, self.0.as_f64()).into())
271 }
272}
273
274impl<'s, T: Numeric> FromV8<'s> for Number<T> {
275 type Error = DataError;
276
277 fn from_v8<'i>(
278 _scope: &mut PinScope<'s, 'i>,
279 value: Local<'s, v8::Value>,
280 ) -> Result<Self, Self::Error> {
281 <Self as FromV8Scopeless>::from_v8(value)
282 }
283}
284
285impl<'s, T: Numeric> FromV8Scopeless<'s> for Number<T> {
286 #[inline]
287 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
288 T::from_value(&value).map(Number).ok_or_else(|| {
289 DataError(v8::DataError::BadType {
290 actual: value.type_repr(),
291 expected: T::NAME,
292 })
293 })
294 }
295}
296
297macro_rules! impl_number_types {
298 ($($t:ty),*) => {
299 $(
300 impl<'a> FromV8<'a> for $t {
301 type Error = DataError;
302 #[inline]
303 fn from_v8<'i>(
304 _scope: &mut v8::PinScope<'a, 'i>,
305 value: v8::Local<'a, v8::Value>,
306 ) -> Result<Self, Self::Error> {
307 <Self as FromV8Scopeless>::from_v8(value)
308 }
309 }
310 impl<'a> FromV8Scopeless<'a> for $t {
311 #[inline]
312 fn from_v8(value: v8::Local<'a, v8::Value>) -> Result<Self, Self::Error> {
313 let n = value.try_cast::<v8::Number>()?;
314 Ok(n.value() as Self)
315 }
316 }
317
318 impl<'a> ToV8<'a> for $t {
319 type Error = Infallible;
320 #[inline]
321 fn to_v8<'i>(
322 self,
323 scope: &mut v8::PinScope<'a, 'i>,
324 ) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
325 Ok(v8::Number::new(scope, self as f64).into())
326 }
327 }
328 )*
329 };
330}
331
332impl_number_types!(
333 u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, f32, f64
334);
335
336#[derive(Debug)]
337pub struct BigInt {
338 pub sign_bit: bool,
339 pub words: Vec<u64>,
340}
341
342impl<'s> ToV8<'s> for BigInt {
343 type Error = JsErrorBox;
344
345 fn to_v8<'i>(
346 self,
347 scope: &mut v8::PinScope<'s, 'i>,
348 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
349 v8::BigInt::new_from_words(scope, self.sign_bit, &self.words)
350 .map(Into::into)
351 .ok_or_else(|| JsErrorBox::type_error("Failed to create BigInt"))
352 }
353}
354
355impl<'s> FromV8<'s> for BigInt {
356 type Error = DataError;
357
358 fn from_v8<'i>(
359 _scope: &mut v8::PinScope<'s, 'i>,
360 value: v8::Local<'s, v8::Value>,
361 ) -> Result<Self, Self::Error> {
362 let bigint = value.try_cast::<v8::BigInt>()?;
363
364 let word_count = bigint.word_count();
365 let mut words = vec![0u64; word_count];
366 let (sign_bit, _) = bigint.to_words_array(&mut words);
367
368 Ok(BigInt { sign_bit, words })
369 }
370}
371
372impl From<num_bigint::BigInt> for BigInt {
373 fn from(big_int: num_bigint::BigInt) -> Self {
374 let (sign, words) = big_int.to_u64_digits();
375 Self {
376 sign_bit: sign == num_bigint::Sign::Minus,
377 words,
378 }
379 }
380}
381
382impl From<BigInt> for num_bigint::BigInt {
383 fn from(big_int: BigInt) -> Self {
384 let (prefix, slice, suffix) = unsafe { big_int.words.align_to::<u32>() };
389 assert!(prefix.is_empty());
390 assert!(suffix.is_empty());
391 assert_eq!(slice.len(), big_int.words.len() * 2);
392 Self::from_slice(
393 if big_int.sign_bit {
394 num_bigint::Sign::Minus
395 } else {
396 num_bigint::Sign::Plus
397 },
398 slice,
399 )
400 }
401}
402
403impl<'s> ToV8<'s> for bool {
404 type Error = Infallible;
405 #[inline]
406 fn to_v8<'i>(
407 self,
408 scope: &mut v8::PinScope<'s, 'i>,
409 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
410 Ok(v8::Boolean::new(scope, self).into())
411 }
412}
413
414impl<'s> FromV8<'s> for bool {
415 type Error = DataError;
416
417 fn from_v8<'i>(
418 _scope: &mut PinScope<'s, 'i>,
419 value: Local<'s, v8::Value>,
420 ) -> Result<Self, Self::Error> {
421 <Self as FromV8Scopeless>::from_v8(value)
422 }
423}
424
425impl<'s> FromV8Scopeless<'s> for bool {
426 #[inline]
427 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
428 value
429 .try_cast::<v8::Boolean>()
430 .map(|v| v.is_true())
431 .map_err(DataError)
432 }
433}
434
435impl<'s> FromV8<'s> for String {
436 type Error = Infallible;
437 #[inline]
438 fn from_v8<'i>(
439 scope: &mut v8::PinScope<'s, 'i>,
440 value: v8::Local<'s, v8::Value>,
441 ) -> Result<String, Self::Error> {
442 Ok(value.to_rust_string_lossy(scope))
443 }
444}
445impl<'s> ToV8<'s> for String {
446 type Error = Infallible;
447 #[inline]
448 fn to_v8<'i>(
449 self,
450 scope: &mut v8::PinScope<'s, 'i>,
451 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
452 Ok(v8::String::new(scope, &self).unwrap().into()) }
454}
455
456impl<'s> ToV8<'s> for &'static str {
457 type Error = Infallible;
458 #[inline]
459 fn to_v8<'i>(
460 self,
461 scope: &mut v8::PinScope<'s, 'i>,
462 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
463 Ok(v8::String::new(scope, self).unwrap().into()) }
465}
466
467impl<'s> ToV8<'s> for Box<str> {
468 type Error = Infallible;
469 #[inline]
470 fn to_v8<'i>(
471 self,
472 scope: &mut v8::PinScope<'s, 'i>,
473 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
474 Ok(v8::String::new(scope, &self).unwrap().into()) }
476}
477
478const USIZE2X: usize = std::mem::size_of::<usize>() * 2;
479#[derive(PartialEq, Eq, Clone, Debug, Default)]
480pub struct ByteString(SmallVec<[u8; USIZE2X]>);
481
482impl Deref for ByteString {
483 type Target = SmallVec<[u8; USIZE2X]>;
484
485 fn deref(&self) -> &Self::Target {
486 &self.0
487 }
488}
489
490impl DerefMut for ByteString {
491 fn deref_mut(&mut self) -> &mut Self::Target {
492 &mut self.0
493 }
494}
495
496impl AsRef<[u8]> for ByteString {
497 fn as_ref(&self) -> &[u8] {
498 &self.0
499 }
500}
501
502impl AsMut<[u8]> for ByteString {
503 fn as_mut(&mut self) -> &mut [u8] {
504 &mut self.0
505 }
506}
507
508impl<'a> ToV8<'a> for ByteString {
509 type Error = Infallible;
510
511 fn to_v8<'i>(
512 self,
513 scope: &mut v8::PinScope<'a, 'i>,
514 ) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
515 let v = v8::String::new_from_one_byte(
516 scope,
517 self.as_ref(),
518 v8::NewStringType::Normal,
519 )
520 .unwrap();
521 Ok(v.into())
522 }
523}
524
525#[derive(Debug, thiserror::Error, deno_error::JsError)]
526#[class(type)]
527pub enum ByteStringError {
528 #[error("Invalid type, expected: string but got: {0}")]
529 ExpectedString(&'static str),
530 #[error("Invalid type, expected: latin1")]
531 ExpectedLatin1,
532}
533
534impl<'a> FromV8<'a> for ByteString {
535 type Error = ByteStringError;
536
537 fn from_v8<'i>(
538 scope: &mut v8::PinScope<'a, 'i>,
539 value: v8::Local<'a, v8::Value>,
540 ) -> Result<Self, Self::Error> {
541 let v8str = v8::Local::<v8::String>::try_from(value)
542 .map_err(|_| ByteStringError::ExpectedString(value.type_repr()))?;
543 if !v8str.contains_only_onebyte() {
544 return Err(ByteStringError::ExpectedLatin1);
545 }
546 let len = v8str.length();
547 let mut buffer = SmallVec::with_capacity(len);
548 #[allow(
549 clippy::uninit_vec,
550 reason = "buffer is immediately written to after set_len"
551 )]
552 unsafe {
555 buffer.set_len(len);
556 v8str.write_one_byte_v2(scope, 0, &mut buffer, v8::WriteFlags::empty());
557 }
558 Ok(Self(buffer))
559 }
560}
561
562impl From<Vec<u8>> for ByteString {
563 fn from(vec: Vec<u8>) -> Self {
564 ByteString(SmallVec::from_vec(vec))
565 }
566}
567
568#[allow(clippy::from_over_into, reason = "cannot implement From for Vec")]
569impl Into<Vec<u8>> for ByteString {
570 fn into(self) -> Vec<u8> {
571 self.0.into_vec()
572 }
573}
574
575impl From<&[u8]> for ByteString {
576 fn from(s: &[u8]) -> Self {
577 ByteString(SmallVec::from_slice(s))
578 }
579}
580
581impl From<&str> for ByteString {
582 fn from(s: &str) -> Self {
583 let v: Vec<u8> = s.into();
584 ByteString::from(v)
585 }
586}
587
588impl From<String> for ByteString {
589 fn from(s: String) -> Self {
590 ByteString::from(s.into_bytes())
591 }
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
595#[repr(transparent)]
597pub struct OptionNull<T>(pub Option<T>);
598
599impl<T> From<Option<T>> for OptionNull<T> {
600 fn from(option: Option<T>) -> Self {
601 Self(option)
602 }
603}
604
605impl<T> From<OptionNull<T>> for Option<T> {
606 fn from(value: OptionNull<T>) -> Self {
607 value.0
608 }
609}
610
611impl<'s, T> ToV8<'s> for OptionNull<T>
612where
613 T: ToV8<'s>,
614{
615 type Error = T::Error;
616
617 fn to_v8<'i>(
618 self,
619 scope: &mut v8::PinScope<'s, 'i>,
620 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
621 match self.0 {
622 Some(value) => value.to_v8(scope),
623 None => Ok(v8::null(scope).into()),
624 }
625 }
626}
627
628impl<'s, T> FromV8<'s> for OptionNull<T>
629where
630 T: FromV8<'s>,
631{
632 type Error = T::Error;
633
634 fn from_v8<'i>(
635 scope: &mut v8::PinScope<'s, 'i>,
636 value: v8::Local<'s, v8::Value>,
637 ) -> Result<Self, Self::Error> {
638 if value.is_null() {
639 Ok(OptionNull(None))
640 } else {
641 T::from_v8(scope, value).map(|v| OptionNull(Some(v)))
642 }
643 }
644}
645
646impl<'s, T> FromV8Scopeless<'s> for OptionNull<T>
647where
648 T: FromV8Scopeless<'s>,
649{
650 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
651 if value.is_null() {
652 Ok(OptionNull(None))
653 } else {
654 <T as FromV8Scopeless>::from_v8(value).map(|v| OptionNull(Some(v)))
655 }
656 }
657}
658
659#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
660#[repr(transparent)]
662pub struct OptionUndefined<T>(pub Option<T>);
663
664impl<T> From<Option<T>> for OptionUndefined<T> {
665 fn from(option: Option<T>) -> Self {
666 Self(option)
667 }
668}
669
670impl<T> From<OptionUndefined<T>> for Option<T> {
671 fn from(value: OptionUndefined<T>) -> Self {
672 value.0
673 }
674}
675
676impl<'s, T> ToV8<'s> for OptionUndefined<T>
677where
678 T: ToV8<'s>,
679{
680 type Error = T::Error;
681
682 fn to_v8<'i>(
683 self,
684 scope: &mut v8::PinScope<'s, 'i>,
685 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
686 match self.0 {
687 Some(value) => value.to_v8(scope),
688 None => Ok(v8::undefined(scope).into()),
689 }
690 }
691}
692
693impl<'s, T> FromV8<'s> for OptionUndefined<T>
694where
695 T: FromV8<'s>,
696{
697 type Error = T::Error;
698
699 fn from_v8<'i>(
700 scope: &mut v8::PinScope<'s, 'i>,
701 value: v8::Local<'s, v8::Value>,
702 ) -> Result<Self, Self::Error> {
703 if value.is_undefined() {
704 Ok(OptionUndefined(None))
705 } else {
706 T::from_v8(scope, value).map(|v| OptionUndefined(Some(v)))
707 }
708 }
709}
710
711impl<'s, T> FromV8Scopeless<'s> for OptionUndefined<T>
712where
713 T: FromV8Scopeless<'s>,
714{
715 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
716 if value.is_undefined() {
717 Ok(OptionUndefined(None))
718 } else {
719 <T as FromV8Scopeless>::from_v8(value).map(|v| OptionUndefined(Some(v)))
720 }
721 }
722}
723
724unsafe fn abview_to_box<T>(
725 ab_view: v8::Local<v8::ArrayBufferView>,
726) -> Box<[T]> {
727 if ab_view.byte_length() == 0 {
728 return Box::new([]);
729 }
730 let data = ab_view.data();
731 let len = ab_view.byte_length() / std::mem::size_of::<T>();
732 let mut out = Box::<[T]>::new_uninit_slice(len);
733 unsafe {
734 std::ptr::copy_nonoverlapping(
735 data.cast::<T>(),
736 out.as_mut_ptr().cast::<T>(),
737 len,
738 );
739 out.assume_init()
740 }
741}
742
743macro_rules! typedarray_to_v8 {
744 ($ty:ty, $v8ty:ident, $v8fn:ident) => {
745 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
746 pub struct $v8ty(pub Box<[$ty]>);
747
748 impl std::ops::Deref for $v8ty {
749 type Target = [$ty];
750 fn deref(&self) -> &Self::Target {
751 &self.0
752 }
753 }
754
755 impl From<Vec<$ty>> for $v8ty {
756 fn from(value: Vec<$ty>) -> Self {
757 Self(value.into_boxed_slice())
758 }
759 }
760
761 impl From<Box<[$ty]>> for $v8ty {
762 fn from(value: Box<[$ty]>) -> Self {
763 Self(value)
764 }
765 }
766
767 impl<'a> ToV8<'a> for $v8ty {
768 type Error = JsErrorBox;
769
770 fn to_v8<'i>(
771 self,
772 scope: &mut v8::PinScope<'a, 'i>,
773 ) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
774 let len = self.0.len();
775 if self.0.is_empty() {
776 let ab = v8::ArrayBuffer::new(scope, 0);
777 return v8::$v8ty::new(scope, ab, 0, 0)
778 .ok_or_else(|| {
779 JsErrorBox::type_error("Failed to create typed array")
780 })
781 .map(|v| v.into());
782 }
783 let backing = v8::ArrayBuffer::new_backing_store_from_bytes(self.0);
784 let backing_shared = backing.make_shared();
785 let ab = v8::ArrayBuffer::with_backing_store(scope, &backing_shared);
786 v8::$v8ty::new(scope, ab, 0, len)
787 .ok_or_else(|| JsErrorBox::type_error("Failed to create typed array"))
788 .map(|v| v.into())
789 }
790 }
791
792 impl<'s> FromV8<'s> for $v8ty {
793 type Error = DataError;
794
795 fn from_v8<'i>(
796 _scope: &mut PinScope<'s, 'i>,
797 value: Local<'s, v8::Value>,
798 ) -> Result<Self, Self::Error> {
799 <Self as FromV8Scopeless>::from_v8(value)
800 }
801 }
802
803 impl<'a> FromV8Scopeless<'a> for $v8ty {
804 fn from_v8(value: v8::Local<'a, v8::Value>) -> Result<Self, Self::Error> {
805 if value.$v8fn() {
806 Ok($v8ty(unsafe {
807 abview_to_box::<$ty>(value.cast::<v8::ArrayBufferView>())
808 }))
809 } else {
810 Err(DataError(v8::DataError::BadType {
811 actual: value.type_repr(),
812 expected: stringify!($v8ty),
813 }))
814 }
815 }
816 }
817 };
818}
819
820typedarray_to_v8!(i8, Int8Array, is_int8_array);
821typedarray_to_v8!(u8, Uint8Array, is_uint8_array);
822typedarray_to_v8!(i16, Int16Array, is_int16_array);
823typedarray_to_v8!(u16, Uint16Array, is_uint16_array);
824typedarray_to_v8!(i32, Int32Array, is_int32_array);
825typedarray_to_v8!(u32, Uint32Array, is_uint32_array);
826typedarray_to_v8!(i64, BigInt64Array, is_big_int64_array);
827typedarray_to_v8!(u64, BigUint64Array, is_big_uint64_array);
828
829pub enum ArrayBufferView {
830 Int8Array(Int8Array),
831 Uint8Array(Uint8Array),
832 Int16Array(Int16Array),
833 Uint16Array(Uint16Array),
834 Int32Array(Int32Array),
835 Uint32Array(Uint32Array),
836 BigInt64Array(BigInt64Array),
837 BigUint64Array(BigUint64Array),
838}
839
840impl<'a> ToV8<'a> for ArrayBufferView {
841 type Error = JsErrorBox;
842
843 fn to_v8<'i>(
844 self,
845 scope: &mut PinScope<'a, 'i>,
846 ) -> Result<Local<'a, v8::Value>, Self::Error> {
847 match self {
848 ArrayBufferView::Int8Array(view) => view.to_v8(scope),
849 ArrayBufferView::Uint8Array(view) => view.to_v8(scope),
850 ArrayBufferView::Int16Array(view) => view.to_v8(scope),
851 ArrayBufferView::Uint16Array(view) => view.to_v8(scope),
852 ArrayBufferView::Int32Array(view) => view.to_v8(scope),
853 ArrayBufferView::Uint32Array(view) => view.to_v8(scope),
854 ArrayBufferView::BigInt64Array(view) => view.to_v8(scope),
855 ArrayBufferView::BigUint64Array(view) => view.to_v8(scope),
856 }
857 }
858}
859
860impl<'s> FromV8<'s> for ArrayBufferView {
861 type Error = DataError;
862
863 fn from_v8<'i>(
864 _scope: &mut PinScope<'s, 'i>,
865 value: Local<'s, v8::Value>,
866 ) -> Result<Self, Self::Error> {
867 <Self as FromV8Scopeless>::from_v8(value)
868 }
869}
870
871impl<'a> FromV8Scopeless<'a> for ArrayBufferView {
872 fn from_v8(value: Local<'a, v8::Value>) -> Result<Self, Self::Error> {
873 if value.is_int8_array() {
874 Ok(Self::Int8Array(<Int8Array as FromV8Scopeless>::from_v8(
875 value,
876 )?))
877 } else if value.is_uint8_array() {
878 Ok(Self::Uint8Array(<Uint8Array as FromV8Scopeless>::from_v8(
879 value,
880 )?))
881 } else if value.is_int16_array() {
882 Ok(Self::Int16Array(<Int16Array as FromV8Scopeless>::from_v8(
883 value,
884 )?))
885 } else if value.is_uint16_array() {
886 Ok(Self::Uint16Array(
887 <Uint16Array as FromV8Scopeless>::from_v8(value)?,
888 ))
889 } else if value.is_int32_array() {
890 Ok(Self::Int32Array(<Int32Array as FromV8Scopeless>::from_v8(
891 value,
892 )?))
893 } else if value.is_uint32_array() {
894 Ok(Self::Uint32Array(
895 <Uint32Array as FromV8Scopeless>::from_v8(value)?,
896 ))
897 } else if value.is_big_int64_array() {
898 Ok(Self::BigInt64Array(
899 <BigInt64Array as FromV8Scopeless>::from_v8(value)?,
900 ))
901 } else if value.is_big_uint64_array() {
902 Ok(Self::BigUint64Array(
903 <BigUint64Array as FromV8Scopeless>::from_v8(value)?,
904 ))
905 } else {
906 Err(DataError(v8::DataError::BadType {
907 actual: value.type_repr(),
908 expected: "ArrayBufferView",
909 }))
910 }
911 }
912}
913
914impl<'a, T> ToV8<'a> for Vec<T>
915where
916 T: ToV8<'a>,
917{
918 type Error = T::Error;
919
920 fn to_v8(
921 self,
922 scope: &mut v8::PinScope<'a, '_>,
923 ) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
924 let buf = self
925 .into_iter()
926 .map(|v| v.to_v8(scope))
927 .collect::<Result<Vec<_>, _>>()?;
928 Ok(v8::Array::new_with_elements(scope, &buf).into())
929 }
930}
931
932impl<'a, T> FromV8<'a> for Vec<T>
933where
934 T: FromV8<'a>,
935{
936 type Error = JsErrorBox;
937
938 fn from_v8(
939 scope: &mut v8::PinScope<'a, '_>,
940 value: v8::Local<'a, v8::Value>,
941 ) -> Result<Self, Self::Error> {
942 let arr = v8::Local::<v8::Array>::try_from(value)
943 .map_err(|e| JsErrorBox::from_err(DataError(e)))?;
944 let len = arr.length() as usize;
945
946 let mut out = maybe_uninit_vec::<T>(len);
947
948 for i in 0..len {
949 let v = arr.get_index(scope, i as u32).unwrap();
950 match T::from_v8(scope, v) {
951 Ok(v) => {
952 out[i].write(v);
953 }
954 Err(e) => {
955 for elem in out.iter_mut().take(i) {
957 unsafe {
959 elem.assume_init_drop();
960 }
961 }
962 return Err(JsErrorBox::from_err(e));
963 }
964 }
965 }
966
967 let out = unsafe { transmute_vec::<MaybeUninit<T>, T>(out) };
970
971 Ok(out)
972 }
973}
974
975fn maybe_uninit_vec<T>(len: usize) -> Vec<std::mem::MaybeUninit<T>> {
976 let mut v = Vec::with_capacity(len);
977 unsafe {
980 v.set_len(len);
981 }
982 v
983}
984
985unsafe fn transmute_vec<T, U>(v: Vec<T>) -> Vec<U> {
990 const {
991 assert!(std::mem::size_of::<T>() == std::mem::size_of::<U>());
992 assert!(std::mem::align_of::<T>() == std::mem::align_of::<U>());
993 }
994
995 let mut v = std::mem::ManuallyDrop::new(v);
997 let len = v.len();
998 let cap = v.capacity();
999 let ptr = v.as_mut_ptr();
1000
1001 unsafe { Vec::from_raw_parts(ptr as *mut U, len, cap) }
1004}
1005
1006macro_rules! impl_tuple {
1007 ($($len: expr; ($($name: ident),*)),+) => {
1008 $(
1009 impl<'a, $($name),+> ToV8<'a> for ($($name,)+)
1010 where
1011 $($name: ToV8<'a>,)+
1012 {
1013 type Error = deno_error::JsErrorBox;
1014 fn to_v8(self, scope: &mut v8::PinScope<'a, '_>) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
1015 #[allow(non_snake_case, reason = "macro-generated bindings match type parameter names")]
1016 let ($($name,)+) = self;
1017 let elements = &[$($name.to_v8(scope).map_err(deno_error::JsErrorBox::from_err)?),+];
1018 Ok(v8::Array::new_with_elements(scope, elements).into())
1019 }
1020 }
1021 impl<'a, $($name),+> FromV8<'a> for ($($name,)+)
1022 where
1023 $($name: FromV8<'a>,)+
1024 {
1025 type Error = deno_error::JsErrorBox;
1026
1027 fn from_v8(
1028 scope: &mut v8::PinScope<'a, '_>,
1029 value: v8::Local<'a, v8::Value>,
1030 ) -> Result<Self, Self::Error> {
1031 let array = v8::Local::<v8::Array>::try_from(value)
1032 .map_err(|e| deno_error::JsErrorBox::from_err(crate::error::DataError(e)))?;
1033 if array.length() != $len {
1034 return Err(deno_error::JsErrorBox::type_error(format!("Expected {} elements, got {}", $len, array.length())));
1035 }
1036 let mut i = 0;
1037 #[allow(non_snake_case, reason = "macro-generated bindings match type parameter names")]
1038 let ($($name,)+) = (
1039 $(
1040 {
1041 let element = array.get_index(scope, i).unwrap();
1042 let res = $name::from_v8(scope, element).map_err(deno_error::JsErrorBox::from_err)?;
1043 #[allow(unused, reason = "counter is used in multi-element tuples")]
1044 {
1045 i += 1;
1046 }
1047 res
1048 },
1049 )+
1050 );
1051 Ok(($($name,)+))
1052 }
1053 }
1054 )+
1055 };
1056}
1057
1058impl_tuple!(
1059 1; (A),
1060 2; (A, B),
1061 3; (A, B, C),
1062 4; (A, B, C, D),
1063 5; (A, B, C, D, E),
1064 6; (A, B, C, D, E, F),
1065 7; (A, B, C, D, E, F, G),
1066 8; (A, B, C, D, E, F, G, H),
1067 9; (A, B, C, D, E, F, G, H, I),
1068 10; (A, B, C, D, E, F, G, H, I, J),
1069 11; (A, B, C, D, E, F, G, H, I, J, K),
1070 12; (A, B, C, D, E, F, G, H, I, J, K, L)
1071);
1072
1073impl<'s, T> ToV8<'s> for Option<T>
1074where
1075 T: ToV8<'s>,
1076{
1077 type Error = T::Error;
1078
1079 fn to_v8<'i>(
1080 self,
1081 scope: &mut v8::PinScope<'s, 'i>,
1082 ) -> Result<v8::Local<'s, v8::Value>, Self::Error> {
1083 match self {
1084 Some(value) => value.to_v8(scope),
1085 None => Ok(v8::null(scope).into()),
1086 }
1087 }
1088}
1089
1090impl<'s, T> FromV8<'s> for Option<T>
1091where
1092 T: FromV8<'s>,
1093{
1094 type Error = T::Error;
1095
1096 fn from_v8<'i>(
1097 scope: &mut v8::PinScope<'s, 'i>,
1098 value: v8::Local<'s, v8::Value>,
1099 ) -> Result<Self, Self::Error> {
1100 if value.is_null_or_undefined() {
1101 Ok(None)
1102 } else {
1103 T::from_v8(scope, value).map(|v| Some(v))
1104 }
1105 }
1106}
1107
1108impl<'s, T> FromV8Scopeless<'s> for Option<T>
1109where
1110 T: FromV8Scopeless<'s>,
1111{
1112 fn from_v8(value: v8::Local<'s, v8::Value>) -> Result<Self, Self::Error> {
1113 if value.is_null_or_undefined() {
1114 Ok(None)
1115 } else {
1116 <T as FromV8Scopeless>::from_v8(value).map(|v| Some(v))
1117 }
1118 }
1119}
1120
1121#[derive(Debug, thiserror::Error, deno_error::JsError)]
1122pub enum V8ConvertError {
1123 #[class(inherit)]
1124 #[error(transparent)]
1125 Infallible(#[from] Infallible),
1126 #[class(inherit)]
1127 #[error(transparent)]
1128 DataError(DataError),
1129}
1130
1131impl From<v8::DataError> for V8ConvertError {
1132 fn from(value: v8::DataError) -> Self {
1133 Self::DataError(value.into())
1134 }
1135}
1136
1137impl<'s, T, E> ToV8<'s> for v8::Global<T>
1138where
1139 Local<'s, T>: TryInto<Local<'s, v8::Value>, Error = E>,
1140 E: Into<V8ConvertError>,
1141{
1142 type Error = V8ConvertError;
1143
1144 fn to_v8<'i>(
1145 self,
1146 scope: &mut PinScope<'s, 'i>,
1147 ) -> Result<Local<'s, v8::Value>, Self::Error> {
1148 let local: Local<'s, T> = Local::new(scope, self);
1149 local.try_into().map_err(Into::into)
1150 }
1151}
1152
1153impl<'s, T, E> FromV8<'s> for v8::Global<T>
1154where
1155 Local<'s, v8::Value>: TryInto<Local<'s, T>, Error = E>,
1156 E: Into<V8ConvertError>,
1157{
1158 type Error = V8ConvertError;
1159
1160 fn from_v8<'i>(
1161 scope: &mut PinScope<'s, 'i>,
1162 value: Local<'s, v8::Value>,
1163 ) -> Result<Self, Self::Error> {
1164 Ok(v8::Global::new(
1165 scope,
1166 value.try_into().map_err(Into::into)?,
1167 ))
1168 }
1169}
1170
1171impl<'s, T, E> ToV8<'s> for v8::Local<'s, T>
1172where
1173 Local<'s, T>: TryInto<Local<'s, v8::Value>, Error = E>,
1174 E: Into<V8ConvertError>,
1175{
1176 type Error = V8ConvertError;
1177
1178 fn to_v8<'i>(
1179 self,
1180 _scope: &mut PinScope<'s, 'i>,
1181 ) -> Result<Local<'s, v8::Value>, Self::Error> {
1182 self.try_into().map_err(Into::into)
1183 }
1184}
1185
1186impl<'s, T, E> FromV8<'s> for v8::Local<'s, T>
1187where
1188 Local<'s, v8::Value>: TryInto<Local<'s, T>, Error = E>,
1189 E: Into<V8ConvertError>,
1190{
1191 type Error = V8ConvertError;
1192
1193 fn from_v8<'i>(
1194 _scope: &mut PinScope<'s, 'i>,
1195 value: Local<'s, v8::Value>,
1196 ) -> Result<Self, Self::Error> {
1197 <Self as FromV8Scopeless>::from_v8(value)
1198 }
1199}
1200
1201impl<'s, T, E> FromV8Scopeless<'s> for v8::Local<'s, T>
1202where
1203 Local<'s, v8::Value>: TryInto<Local<'s, T>, Error = E>,
1204 E: Into<V8ConvertError>,
1205{
1206 fn from_v8(value: Local<'s, v8::Value>) -> Result<Self, Self::Error> {
1207 value.try_into().map_err(Into::into)
1208 }
1209}
1210
1211#[cfg(all(test, not(miri)))]
1212mod tests {
1213 use std::collections::HashMap;
1214 use std::sync::atomic::AtomicUsize;
1215 use std::sync::atomic::Ordering;
1216
1217 use deno_error::JsErrorClass;
1218 use v8::Local;
1219
1220 use super::*;
1221 use crate::JsRuntime;
1222 use crate::scope as scope_macro;
1223
1224 static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1225
1226 fn next_id() -> usize {
1227 ID_COUNTER.fetch_add(1, Ordering::Relaxed)
1228 }
1229
1230 static ASSERT_CODE: &str = r#"
1232function equal(a, b) {
1233 if (a === b) return true;
1234 if (typeof a !== typeof b) return false;
1235 if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((v, i) => equal(v, b[i]));
1236 if (typeof a === 'object' && typeof b === 'object') {
1237 const keysA = Object.keys(a);
1238 const keysB = Object.keys(b);
1239 if (keysA.length !== keysB.length) return false;
1240 for (const key of keysA) {
1241 if (!equal(a[key], b[key])) return false;
1242 }
1243 return true;
1244 }
1245 return false;
1246}
1247"#;
1248
1249 fn cast_closure<F>(f: F) -> F
1250 where
1251 F: for<'a, 'b> Fn(
1252 &mut v8::PinScope<'a, 'b>,
1253 v8::FunctionCallbackArguments<'a>,
1254 v8::ReturnValue<'a>,
1255 ) + 'static,
1256 {
1257 f
1258 }
1259
1260 fn key<'a>(
1261 scope: &mut v8::PinScope<'a, '_>,
1262 name: &str,
1263 ) -> v8::Local<'a, v8::Value> {
1264 v8::String::new(scope, name).unwrap().into()
1265 }
1266
1267 macro_rules! make_test_fn {
1268 ($scope:expr, $f:expr) => {
1269 let global = $scope.get_current_context().global($scope);
1270 let test_fn_key = key($scope, "test_fn");
1271 let test_fn = v8::FunctionBuilder::<v8::Function>::new(cast_closure($f))
1272 .build($scope)
1273 .unwrap();
1274 global.set($scope, test_fn_key, test_fn.into()).unwrap();
1275 };
1276 }
1277
1278 macro_rules! to_v8_test {
1279 ($runtime:ident, |$scope: ident, $args: ident| $to_v8:expr, $assertion:expr) => {{
1280 scope_macro!($scope, &mut $runtime);
1281 make_test_fn!($scope, |$scope, $args, mut rv| {
1282 let v = $to_v8;
1283 rv.set(v);
1284 });
1285 }
1286 {
1287 let test_name = format!("test_{}", next_id());
1288 let assertion = format!("{}{};", ASSERT_CODE, $assertion);
1289 let result = $runtime.execute_script(test_name, assertion).unwrap();
1290 scope_macro!(scope, &mut $runtime);
1291 let local = v8::Local::new(scope, result);
1292 assert!(local.is_true());
1293 }};
1294 }
1295
1296 macro_rules! from_v8_test {
1297 ($runtime:ident, $js:expr, |$scope: ident, $result: ident| $assertion:expr) => {{
1298 let js = format!("{}{};", ASSERT_CODE, $js);
1299 let $result = $runtime
1300 .execute_script(format!("test_{}", next_id()), js)
1301 .unwrap();
1302 scope_macro!($scope, &mut $runtime);
1303 let $result = v8::Local::new($scope, $result);
1304 $assertion;
1305 }};
1306 }
1307
1308 #[test]
1309 fn test_option_undefined() {
1310 let mut runtime = JsRuntime::new(Default::default());
1311
1312 to_v8_test!(
1313 runtime,
1314 |scope, _args| OptionUndefined::<Number<f64>>(None).to_v8(scope).unwrap(),
1315 "test_fn() === undefined"
1316 );
1317 to_v8_test!(
1318 runtime,
1319 |scope, _args| OptionUndefined::<Number<f64>>(Some(Number(1.0)))
1320 .to_v8(scope)
1321 .unwrap(),
1322 "test_fn() === 1.0"
1323 );
1324 from_v8_test!(runtime, "undefined", |scope, result| {
1325 let r = <OptionUndefined<Number<f64>> as FromV8>::from_v8(scope, result)
1326 .unwrap();
1327 assert_eq!(r, OptionUndefined(None));
1328 });
1329
1330 from_v8_test!(runtime, "1.0", |scope, result| {
1331 assert_eq!(
1332 <OptionUndefined::<Number<f64>> as FromV8>::from_v8(scope, result)
1333 .unwrap(),
1334 OptionUndefined(Some(Number(1.0)))
1335 )
1336 });
1337 }
1338
1339 #[test]
1340 fn test_option_null() {
1341 let mut runtime = JsRuntime::new(Default::default());
1342
1343 to_v8_test!(
1344 runtime,
1345 |scope, _args| OptionNull::<Number<f64>>(None).to_v8(scope).unwrap(),
1346 "test_fn() === null"
1347 );
1348
1349 to_v8_test!(
1350 runtime,
1351 |scope, _args| {
1352 OptionNull::<Number<f64>>(Some(Number(1.0)))
1353 .to_v8(scope)
1354 .unwrap()
1355 },
1356 "test_fn() === 1.0"
1357 );
1358
1359 from_v8_test!(runtime, "null", |scope, result| assert_eq!(
1360 <OptionNull::<Number<f64>> as FromV8>::from_v8(scope, result).unwrap(),
1361 OptionNull(None)
1362 ));
1363
1364 from_v8_test!(runtime, "1.0", |scope, result| assert_eq!(
1365 <OptionNull::<Number<f64>> as FromV8>::from_v8(scope, result).unwrap(),
1366 OptionNull(Some(Number(1.0)))
1367 ));
1368 }
1369
1370 #[test]
1371 fn test_tuple() {
1372 let mut runtime = JsRuntime::new(Default::default());
1373
1374 to_v8_test!(
1375 runtime,
1376 |scope, _args| (Number(1.0), Number(2.0)).to_v8(scope).unwrap(),
1377 "var result = test_fn(); equal(result, [1.0, 2.0])"
1378 );
1379
1380 to_v8_test!(
1381 runtime,
1382 |scope, _args| (Number(1.0), true).to_v8(scope).unwrap(),
1383 "var result = test_fn(); equal(result, [1.0, true])"
1384 );
1385
1386 to_v8_test!(
1387 runtime,
1388 |scope, _args| (
1389 Number(1.0),
1390 Number(2.0),
1391 OptionNull::<Number<f64>>(Some(Number(3.0))),
1392 OptionUndefined::<bool>(None)
1393 )
1394 .to_v8(scope)
1395 .unwrap(),
1396 "equal(test_fn(), [1.0, 2.0, 3.0, undefined])"
1397 );
1398
1399 from_v8_test!(runtime, "[1.0, 2.0]", |scope, result| {
1400 assert_eq!(
1401 <(Number<f64>, Number<f64>)>::from_v8(scope, result).unwrap(),
1402 (Number(1.0), Number(2.0))
1403 )
1404 });
1405
1406 from_v8_test!(runtime, "[1.0, 2.0, 3.0, undefined]", |scope, result| {
1407 assert_eq!(
1408 <(
1409 Number<f64>,
1410 Number<f64>,
1411 OptionNull::<Number<f64>>,
1412 OptionUndefined::<bool>
1413 )>::from_v8(scope, result)
1414 .unwrap(),
1415 (
1416 Number(1.0),
1417 Number(2.0),
1418 OptionNull(Some(Number(3.0))),
1419 OptionUndefined(None)
1420 )
1421 )
1422 });
1423
1424 from_v8_test!(runtime, "[1.0]", |scope, result| {
1425 let err = <(Number<f64>, bool)>::from_v8(scope, result).unwrap_err();
1426 assert!(
1427 err.to_string().contains("Expected 2 elements"),
1428 "expected length mismatch error, got: {}",
1429 err
1430 );
1431 });
1432 }
1433
1434 #[test]
1435 fn test_vec() {
1436 let mut runtime = JsRuntime::new(Default::default());
1437
1438 to_v8_test!(
1439 runtime,
1440 |scope, _args| vec![Number(1.0), Number(2.0)].to_v8(scope).unwrap(),
1441 "equal(test_fn(), [1.0, 2.0])"
1442 );
1443
1444 from_v8_test!(runtime, "[1.0, 2.0]", |scope, result| {
1445 assert_eq!(
1446 <Vec<Number<f64>>>::from_v8(scope, result).unwrap(),
1447 vec![Number(1.0), Number(2.0)]
1448 )
1449 });
1450
1451 to_v8_test!(
1452 runtime,
1453 |scope, _args| Vec::<Number<f64>>::new().to_v8(scope).unwrap(),
1454 "equal(test_fn(), [])"
1455 );
1456
1457 from_v8_test!(runtime, "[]", |scope, result| {
1458 let v = <Vec<Number<f64>>>::from_v8(scope, result).unwrap();
1459 assert_eq!(v, vec![]);
1460 });
1461
1462 to_v8_test!(
1464 runtime,
1465 |scope, _args| vec![vec![Number(1.0), Number(2.0)], vec![Number(3.0)]]
1466 .to_v8(scope)
1467 .unwrap(),
1468 "equal(test_fn(), [[1.0,2.0],[3.0]])"
1469 );
1470 from_v8_test!(runtime, "[[1.0,2.0],[3.0]]", |scope, result| {
1471 let v = <Vec<Vec<Number<f64>>>>::from_v8(scope, result).unwrap();
1472 assert_eq!(v, vec![vec![Number(1.0), Number(2.0)], vec![Number(3.0)]]);
1473 });
1474
1475 to_v8_test!(
1477 runtime,
1478 |scope, _args| vec![Some(Number(1.0)), None, Some(Number(2.0))]
1479 .to_v8(scope)
1480 .unwrap(),
1481 "equal(test_fn(), [1.0, null, 2.0])"
1482 );
1483 from_v8_test!(runtime, "[1.0, undefined, 2.0]", |scope, result| {
1484 let v = <Vec<Option<Number<f64>>>>::from_v8(scope, result).unwrap();
1485 assert_eq!(v, vec![Some(Number(1.0)), None, Some(Number(2.0))]);
1486 });
1487
1488 from_v8_test!(runtime, "[1.0, 'notanumber']", |scope, result| {
1490 let err = <Vec<Number<f64>>>::from_v8(scope, result).unwrap_err();
1491 let err = err.get_ref().downcast_ref::<DataError>().unwrap();
1492 assert_eq!(
1493 err,
1494 &DataError(v8::DataError::BadType {
1495 actual: "string",
1496 expected: "f64",
1497 })
1498 );
1499 });
1500 }
1501
1502 #[test]
1503 fn test_uint8array() {
1504 let mut runtime = JsRuntime::new(Default::default());
1505
1506 to_v8_test!(
1507 runtime,
1508 |scope, _args| Uint8Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1509 "equal(test_fn(), new Uint8Array([1, 2, 3]))"
1510 );
1511
1512 to_v8_test!(
1513 runtime,
1514 |scope, _args| Uint8Array::from(Vec::<u8>::new()).to_v8(scope).unwrap(),
1515 "equal(test_fn(), new Uint8Array([]))"
1516 );
1517
1518 from_v8_test!(runtime, "new Uint8Array([1, 2, 3])", |scope, result| {
1519 assert_eq!(
1520 *<Uint8Array as FromV8>::from_v8(scope, result).unwrap(),
1521 vec![1u8, 2, 3]
1522 )
1523 });
1524
1525 from_v8_test!(runtime, "new Uint8Array([])", |scope, result| {
1526 assert_eq!(
1527 *<Uint8Array as FromV8>::from_v8(scope, result).unwrap(),
1528 Vec::<u8>::new()
1529 )
1530 });
1531
1532 from_v8_test!(
1533 runtime,
1534 "new Uint8Array([1, 2, 3, 4, 5]).subarray(2)",
1535 |scope, result| {
1536 assert_eq!(
1537 *<Uint8Array as FromV8>::from_v8(scope, result).unwrap(),
1538 vec![3u8, 4, 5]
1539 )
1540 }
1541 );
1542
1543 from_v8_test!(
1544 runtime,
1545 "new Uint8Array([1, 2, 3, 4, 5]).subarray(1, 4)",
1546 |scope, result| {
1547 assert_eq!(
1548 *<Uint8Array as FromV8>::from_v8(scope, result).unwrap(),
1549 vec![2u8, 3, 4]
1550 )
1551 }
1552 );
1553
1554 from_v8_test!(
1555 runtime,
1556 "new Uint8Array([1, 2, 3]).subarray(2, 2)",
1557 |scope, result| {
1558 assert_eq!(
1559 *<Uint8Array as FromV8>::from_v8(scope, result).unwrap(),
1560 Vec::<u8>::new()
1561 )
1562 }
1563 );
1564 }
1565
1566 #[test]
1567 fn test_uint16array() {
1568 let mut runtime = JsRuntime::new(Default::default());
1569
1570 to_v8_test!(
1571 runtime,
1572 |scope, _args| Uint16Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1573 "equal(test_fn(), new Uint16Array([1, 2, 3]))"
1574 );
1575
1576 from_v8_test!(runtime, "new Uint16Array([1, 2, 3])", |scope, result| {
1577 assert_eq!(
1578 *<Uint16Array as FromV8>::from_v8(scope, result).unwrap(),
1579 vec![1u16, 2, 3]
1580 )
1581 });
1582
1583 from_v8_test!(runtime, "new Uint16Array([])", |scope, result| {
1584 assert_eq!(
1585 *<Uint16Array as FromV8>::from_v8(scope, result).unwrap(),
1586 Vec::<u16>::new()
1587 )
1588 });
1589
1590 from_v8_test!(
1591 runtime,
1592 "new Uint16Array([1, 2, 3, 4, 5]).subarray(2)",
1593 |scope, result| {
1594 assert_eq!(
1595 *<Uint16Array as FromV8>::from_v8(scope, result).unwrap(),
1596 vec![3u16, 4, 5]
1597 )
1598 }
1599 );
1600
1601 from_v8_test!(
1602 runtime,
1603 "new Uint16Array([1, 2, 3, 4, 5]).subarray(1, 4)",
1604 |scope, result| {
1605 assert_eq!(
1606 *<Uint16Array as FromV8>::from_v8(scope, result).unwrap(),
1607 vec![2u16, 3, 4]
1608 )
1609 }
1610 );
1611 }
1612
1613 #[test]
1614 fn test_uint32array() {
1615 let mut runtime = JsRuntime::new(Default::default());
1616
1617 to_v8_test!(
1618 runtime,
1619 |scope, _args| Uint32Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1620 "equal(test_fn(), new Uint32Array([1, 2, 3]))"
1621 );
1622
1623 from_v8_test!(runtime, "new Uint32Array([1, 2, 3])", |scope, result| {
1624 assert_eq!(
1625 *<Uint32Array as FromV8>::from_v8(scope, result).unwrap(),
1626 vec![1u32, 2, 3]
1627 )
1628 });
1629
1630 from_v8_test!(runtime, "new Uint32Array([])", |scope, result| {
1631 assert_eq!(
1632 *<Uint32Array as FromV8>::from_v8(scope, result).unwrap(),
1633 Vec::<u32>::new()
1634 )
1635 });
1636
1637 from_v8_test!(
1638 runtime,
1639 "new Uint32Array([1, 2, 3, 4, 5]).subarray(2)",
1640 |scope, result| {
1641 assert_eq!(
1642 *<Uint32Array as FromV8>::from_v8(scope, result).unwrap(),
1643 vec![3u32, 4, 5]
1644 )
1645 }
1646 );
1647
1648 from_v8_test!(
1649 runtime,
1650 "new Uint32Array([1, 2, 3, 4, 5]).subarray(1, 4)",
1651 |scope, result| {
1652 assert_eq!(
1653 *<Uint32Array as FromV8>::from_v8(scope, result).unwrap(),
1654 vec![2u32, 3, 4]
1655 )
1656 }
1657 );
1658 }
1659
1660 #[test]
1661 fn test_int32array() {
1662 let mut runtime = JsRuntime::new(Default::default());
1663
1664 to_v8_test!(
1665 runtime,
1666 |scope, _args| Int32Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1667 "equal(test_fn(), new Int32Array([1, 2, 3]))"
1668 );
1669
1670 from_v8_test!(runtime, "new Int32Array([1, 2, 3])", |scope, result| {
1671 assert_eq!(
1672 *<Int32Array as FromV8>::from_v8(scope, result).unwrap(),
1673 vec![1, 2, 3]
1674 )
1675 });
1676
1677 from_v8_test!(runtime, "new Int32Array([])", |scope, result| {
1678 assert_eq!(
1679 *<Int32Array as FromV8>::from_v8(scope, result).unwrap(),
1680 Vec::<i32>::new()
1681 )
1682 });
1683
1684 from_v8_test!(
1685 runtime,
1686 "new Int32Array([1, 2, 3, 4, 5]).subarray(2)",
1687 |scope, result| {
1688 assert_eq!(
1689 *<Int32Array as FromV8>::from_v8(scope, result).unwrap(),
1690 vec![3i32, 4, 5]
1691 )
1692 }
1693 );
1694
1695 from_v8_test!(
1696 runtime,
1697 "new Int32Array([-1, -2, -3, -4, -5]).subarray(1, 4)",
1698 |scope, result| {
1699 assert_eq!(
1700 *<Int32Array as FromV8>::from_v8(scope, result).unwrap(),
1701 vec![-2i32, -3, -4]
1702 )
1703 }
1704 );
1705 }
1706
1707 #[test]
1708 fn test_biguint64array() {
1709 let mut runtime = JsRuntime::new(Default::default());
1710
1711 to_v8_test!(
1712 runtime,
1713 |scope, _args| BigUint64Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1714 "equal(test_fn(), new BigUint64Array([1n, 2n, 3n]))"
1715 );
1716
1717 from_v8_test!(
1718 runtime,
1719 "new BigUint64Array([1n, 2n, 3n])",
1720 |scope, result| {
1721 assert_eq!(
1722 *<BigUint64Array as FromV8>::from_v8(scope, result).unwrap(),
1723 vec![1u64, 2, 3]
1724 )
1725 }
1726 );
1727
1728 from_v8_test!(
1729 runtime,
1730 "new BigUint64Array([1n, 2n, 3n, 4n, 5n]).subarray(2)",
1731 |scope, result| {
1732 assert_eq!(
1733 *<BigUint64Array as FromV8>::from_v8(scope, result).unwrap(),
1734 vec![3u64, 4, 5]
1735 )
1736 }
1737 );
1738
1739 from_v8_test!(
1740 runtime,
1741 "new BigUint64Array([1n, 2n, 3n, 4n, 5n]).subarray(1, 4)",
1742 |scope, result| {
1743 assert_eq!(
1744 *<BigUint64Array as FromV8>::from_v8(scope, result).unwrap(),
1745 vec![2u64, 3, 4]
1746 )
1747 }
1748 );
1749 }
1750
1751 #[test]
1752 fn test_bigint64array() {
1753 let mut runtime = JsRuntime::new(Default::default());
1754
1755 to_v8_test!(
1756 runtime,
1757 |scope, _args| BigInt64Array::from(vec![1, 2, 3]).to_v8(scope).unwrap(),
1758 "equal(test_fn(), new BigInt64Array([1n, 2n, 3n]))"
1759 );
1760
1761 from_v8_test!(
1762 runtime,
1763 "new BigInt64Array([1n, 2n, 3n])",
1764 |scope, result| {
1765 assert_eq!(
1766 *<BigInt64Array as FromV8>::from_v8(scope, result).unwrap(),
1767 vec![1, 2, 3]
1768 )
1769 }
1770 );
1771
1772 from_v8_test!(runtime, "new BigInt64Array([])", |scope, result| {
1773 assert_eq!(
1774 *<BigInt64Array as FromV8>::from_v8(scope, result).unwrap(),
1775 Vec::<i64>::new()
1776 )
1777 });
1778
1779 from_v8_test!(
1780 runtime,
1781 "new BigInt64Array([1n, 2n, 3n, 4n, 5n]).subarray(2)",
1782 |scope, result| {
1783 assert_eq!(
1784 *<BigInt64Array as FromV8>::from_v8(scope, result).unwrap(),
1785 vec![3i64, 4, 5]
1786 )
1787 }
1788 );
1789
1790 from_v8_test!(
1791 runtime,
1792 "new BigInt64Array([-1n, -2n, -3n, -4n, -5n]).subarray(1, 4)",
1793 |scope, result| {
1794 assert_eq!(
1795 *<BigInt64Array as FromV8>::from_v8(scope, result).unwrap(),
1796 vec![-2i64, -3, -4]
1797 )
1798 }
1799 );
1800 }
1801
1802 #[test]
1803 fn derive_struct() {
1804 #[derive(deno_ops::FromV8, deno_ops::ToV8, Eq, PartialEq, Clone, Debug)]
1805 pub struct Struct {
1806 a: u8,
1807 #[from_v8(default = Some(3))]
1808 c: Option<u32>,
1809 #[v8(rename = "e")]
1810 f: String,
1811 #[v8(serde)]
1812 b: HashMap<String, u32>,
1813 }
1814
1815 let mut runtime = JsRuntime::new(Default::default());
1816 deno_core::scope!(scope, runtime);
1817
1818 let value = Struct {
1819 a: 242,
1820 c: Some(102),
1821 f: "foo".to_string(),
1822 b: Default::default(),
1823 };
1824 let to = ToV8::to_v8(value.clone(), scope).unwrap();
1825 let from = FromV8::from_v8(scope, to).unwrap();
1826 assert_eq!(value, from);
1827 }
1828
1829 #[test]
1830 fn derive_from_struct() {
1831 #[derive(deno_ops::FromV8, Eq, PartialEq, Clone, Debug)]
1832 pub struct Struct {
1833 a: u8,
1834 #[from_v8(default = Some(3))]
1835 c: Option<u32>,
1836 #[v8(rename = "e")]
1837 f: String,
1838 #[v8(serde)]
1839 b: HashMap<String, u32>,
1840 }
1841
1842 let mut runtime = JsRuntime::new(Default::default());
1843 let val = runtime
1844 .execute_script("", "({ a: 1, c: 70000, e: 'foo', b: { 'bar': 1 } })")
1845 .unwrap();
1846
1847 let val2 = runtime
1848 .execute_script("", "({ a: 1, e: 'foo', b: {} })")
1849 .unwrap();
1850
1851 deno_core::scope!(scope, runtime);
1852
1853 let val = Local::new(scope, val);
1854 let from = Struct::from_v8(scope, val).unwrap();
1855 assert_eq!(
1856 from,
1857 Struct {
1858 a: 1,
1859 c: Some(70000),
1860 f: "foo".to_string(),
1861 b: HashMap::from([("bar".to_string(), 1)]),
1862 }
1863 );
1864
1865 let val2 = Local::new(scope, val2);
1866 let from = Struct::from_v8(scope, val2).unwrap();
1867 assert_eq!(
1868 from,
1869 Struct {
1870 a: 1,
1871 c: Some(3),
1872 f: "foo".to_string(),
1873 b: HashMap::default(),
1874 }
1875 );
1876 }
1877
1878 #[test]
1879 fn derive_from_tuple_struct() {
1880 #[derive(deno_ops::FromV8, Eq, PartialEq, Clone, Debug)]
1881 pub struct Tuple(u8, String);
1882 #[derive(deno_ops::FromV8, Eq, PartialEq, Clone, Debug)]
1883 pub struct TupleSingle(u8);
1884
1885 let mut runtime = JsRuntime::new(Default::default());
1886 let val = runtime.execute_script("", "([1, 'foo'])").unwrap();
1887 let val2 = runtime.execute_script("", "(1)").unwrap();
1888
1889 deno_core::scope!(scope, runtime);
1890 let val = Local::new(scope, val);
1891
1892 let from = Tuple::from_v8(scope, val).unwrap();
1893 assert_eq!(from, Tuple(1, "foo".to_string()));
1894
1895 let val2 = Local::new(scope, val2);
1896
1897 let from = TupleSingle::from_v8(scope, val2).unwrap();
1898 assert_eq!(from, TupleSingle(1));
1899 }
1900
1901 #[test]
1902 fn derive_to_struct() {
1903 #[derive(deno_ops::ToV8, Eq, PartialEq, Clone, Debug)]
1904 pub struct Struct {
1905 a: u8,
1906 c: Option<u32>,
1907 #[v8(rename = "e")]
1908 f: String,
1909 #[v8(serde)]
1910 b: HashMap<String, u32>,
1911 }
1912
1913 let mut runtime = JsRuntime::new(Default::default());
1914 deno_core::scope!(scope, runtime);
1915
1916 let from = ToV8::to_v8(
1917 Struct {
1918 a: 1,
1919 c: Some(70000),
1920 f: "foo".to_string(),
1921 b: HashMap::from([("bar".to_string(), 1)]),
1922 },
1923 scope,
1924 )
1925 .unwrap();
1926 let obj = from.cast::<v8::Object>();
1927 let key = v8::String::new(scope, "a").unwrap();
1928 assert_eq!(
1929 obj
1930 .get(scope, key.into())
1931 .unwrap()
1932 .number_value(scope)
1933 .unwrap(),
1934 1.0
1935 );
1936 let key = v8::String::new(scope, "c").unwrap();
1937 assert_eq!(
1938 obj
1939 .get(scope, key.into())
1940 .unwrap()
1941 .number_value(scope)
1942 .unwrap(),
1943 70000.0
1944 );
1945 let key = v8::String::new(scope, "e").unwrap();
1946 assert_eq!(
1947 obj
1948 .get(scope, key.into())
1949 .unwrap()
1950 .to_rust_string_lossy(scope),
1951 "foo"
1952 );
1953 let key = v8::String::new(scope, "b").unwrap();
1954 let record_key = v8::String::new(scope, "bar").unwrap();
1955 assert_eq!(
1956 obj
1957 .get(scope, key.into())
1958 .unwrap()
1959 .cast::<v8::Object>()
1960 .get(scope, record_key.into())
1961 .unwrap()
1962 .number_value(scope)
1963 .unwrap(),
1964 1.0
1965 );
1966
1967 let from = ToV8::to_v8(
1968 Struct {
1969 a: 1,
1970 c: Some(3),
1971 f: "foo".to_string(),
1972 b: HashMap::default(),
1973 },
1974 scope,
1975 )
1976 .unwrap();
1977 let obj = from.cast::<v8::Object>();
1978 let key = v8::String::new(scope, "a").unwrap();
1979 assert_eq!(
1980 obj
1981 .get(scope, key.into())
1982 .unwrap()
1983 .number_value(scope)
1984 .unwrap(),
1985 1.0
1986 );
1987 let key = v8::String::new(scope, "c").unwrap();
1988 assert_eq!(
1989 obj
1990 .get(scope, key.into())
1991 .unwrap()
1992 .number_value(scope)
1993 .unwrap(),
1994 3.0
1995 );
1996 let key = v8::String::new(scope, "e").unwrap();
1997 assert_eq!(
1998 obj
1999 .get(scope, key.into())
2000 .unwrap()
2001 .to_rust_string_lossy(scope),
2002 "foo"
2003 );
2004 let key = v8::String::new(scope, "b").unwrap();
2005 assert!(
2006 obj
2007 .get(scope, key.into())
2008 .unwrap()
2009 .try_cast::<v8::Object>()
2010 .is_ok()
2011 );
2012 }
2013
2014 #[test]
2015 fn derive_to_tuple_struct() {
2016 #[derive(deno_ops::ToV8, Eq, PartialEq, Clone, Debug)]
2017 pub struct Tuple(u8, String);
2018 #[derive(deno_ops::ToV8, Eq, PartialEq, Clone, Debug)]
2019 pub struct TupleSingle(u8);
2020
2021 let mut runtime = JsRuntime::new(Default::default());
2022 deno_core::scope!(scope, runtime);
2023
2024 let from = ToV8::to_v8(Tuple(1, "foo".to_string()), scope).unwrap();
2025 let arr = from.cast::<v8::Array>();
2026 assert_eq!(
2027 arr
2028 .get_index(scope, 0)
2029 .unwrap()
2030 .number_value(scope)
2031 .unwrap(),
2032 1.0
2033 );
2034 assert_eq!(
2035 arr.get_index(scope, 1).unwrap().to_rust_string_lossy(scope),
2036 "foo"
2037 );
2038
2039 let from = ToV8::to_v8(TupleSingle(1), scope).unwrap();
2040 assert_eq!(from.number_value(scope).unwrap(), 1.0);
2041 }
2042
2043 #[test]
2044 fn test_bigint() {
2045 let mut runtime = JsRuntime::new(Default::default());
2046
2047 to_v8_test!(
2048 runtime,
2049 |scope, _args| BigInt {
2050 sign_bit: false,
2051 words: vec![42],
2052 }
2053 .to_v8(scope)
2054 .unwrap(),
2055 "test_fn() === 42n"
2056 );
2057
2058 to_v8_test!(
2059 runtime,
2060 |scope, _args| BigInt {
2061 sign_bit: true,
2062 words: vec![42],
2063 }
2064 .to_v8(scope)
2065 .unwrap(),
2066 "test_fn() === -42n"
2067 );
2068
2069 to_v8_test!(
2070 runtime,
2071 |scope, _args| BigInt {
2072 sign_bit: false,
2073 words: vec![0],
2074 }
2075 .to_v8(scope)
2076 .unwrap(),
2077 "test_fn() === 0n"
2078 );
2079
2080 to_v8_test!(
2081 runtime,
2082 |scope, _args| BigInt {
2083 sign_bit: false,
2084 words: vec![0, 1],
2085 }
2086 .to_v8(scope)
2087 .unwrap(),
2088 "test_fn() === 18446744073709551616n"
2089 );
2090
2091 from_v8_test!(runtime, "42n", |scope, result| {
2092 let bigint = BigInt::from_v8(scope, result).unwrap();
2093 assert!(!bigint.sign_bit);
2094 assert_eq!(bigint.words, vec![42]);
2095 });
2096
2097 from_v8_test!(runtime, "-42n", |scope, result| {
2098 let bigint = BigInt::from_v8(scope, result).unwrap();
2099 assert!(bigint.sign_bit);
2100 assert_eq!(bigint.words, vec![42]);
2101 });
2102
2103 from_v8_test!(runtime, "0n", |scope, result| {
2104 let bigint = BigInt::from_v8(scope, result).unwrap();
2105 assert!(!bigint.sign_bit);
2106 assert!(bigint.words.is_empty());
2107 });
2108
2109 from_v8_test!(runtime, "18446744073709551616n", |scope, result| {
2110 let bigint = BigInt::from_v8(scope, result).unwrap();
2111 assert!(!bigint.sign_bit);
2112 assert_eq!(bigint.words, vec![0, 1]);
2113 });
2114
2115 from_v8_test!(
2116 runtime,
2117 "123456789012345678901234567890n",
2118 |scope, result| {
2119 let bigint = BigInt::from_v8(scope, result).unwrap();
2120 let to_v8 = bigint.to_v8(scope).unwrap();
2121 let back = BigInt::from_v8(scope, to_v8).unwrap();
2122
2123 assert!(!back.sign_bit);
2124 assert!(!back.words.is_empty());
2125 }
2126 );
2127 }
2128}