1use crate::{
3 Context, JsExpect, JsResult, JsString, JsValue,
4 builtins::{
5 BuiltInConstructor,
6 array_buffer::AlignedVec,
7 typed_array::{BuiltinTypedArray, TypedArray, TypedArrayKind},
8 },
9 error::JsNativeError,
10 object::{JsArrayBuffer, JsFunction, JsObject, JsSharedArrayBuffer},
11 value::{IntoOrUndefined, TryFromJs},
12};
13use boa_gc::{Finalize, Trace};
14use std::ops::Deref;
15use std::sync::atomic::Ordering;
16
17#[derive(Debug, Clone, Trace, Finalize)]
20pub struct JsTypedArray {
21 inner: JsObject,
22}
23
24impl JsTypedArray {
25 #[inline]
31 pub fn from_object(object: JsObject) -> JsResult<Self> {
32 if object.is::<TypedArray>() {
33 Ok(Self { inner: object })
34 } else {
35 Err(JsNativeError::typ()
36 .with_message("object is not a TypedArray")
37 .into())
38 }
39 }
40
41 #[inline]
44 #[must_use]
45 pub fn kind(&self) -> Option<TypedArrayKind> {
46 self.inner
47 .downcast_ref::<TypedArray>()
48 .map(|arr| arr.kind())
49 }
50
51 #[inline]
59 pub fn length(&self, context: &mut Context) -> JsResult<usize> {
60 Ok(
61 BuiltinTypedArray::length(&self.inner.clone().into(), &[], context)?
62 .as_number()
63 .js_expect("length should return a number")? as usize,
64 )
65 }
66
67 #[inline]
69 pub fn is_empty(&self, context: &mut Context) -> JsResult<bool> {
70 Ok(self.length(context)? == 0)
71 }
72
73 pub fn at<T>(&self, index: T, context: &mut Context) -> JsResult<JsValue>
75 where
76 T: Into<i64>,
77 {
78 BuiltinTypedArray::at(&self.inner.clone().into(), &[index.into().into()], context)
79 }
80
81 #[inline]
102 pub fn buffer(&self, context: &mut Context) -> JsResult<JsValue> {
103 BuiltinTypedArray::buffer(&self.inner.clone().into(), &[], context)
104 }
105
106 #[inline]
112 pub fn byte_length(&self, context: &mut Context) -> JsResult<usize> {
113 Ok(
114 BuiltinTypedArray::byte_length(&self.inner.clone().into(), &[], context)?
115 .as_number()
116 .js_expect("byteLength should return a number")? as usize,
117 )
118 }
119
120 #[inline]
126 pub fn byte_offset(&self, context: &mut Context) -> JsResult<usize> {
127 Ok(
128 BuiltinTypedArray::byte_offset(&self.inner.clone().into(), &[], context)?
129 .as_number()
130 .js_expect("byteLength should return a number")? as usize,
131 )
132 }
133
134 #[inline]
158 pub fn constructor(&self, context: &mut Context) -> JsResult<JsValue> {
159 BuiltinTypedArray::constructor(&self.inner.clone().into(), &[], context)
160 }
161
162 #[inline]
189 pub fn copy_within<T>(
190 &self,
191 target: T,
192 start: u64,
193 end: Option<u64>,
194 context: &mut Context,
195 ) -> JsResult<Self>
196 where
197 T: Into<JsValue>,
198 {
199 let object = BuiltinTypedArray::copy_within(
200 &self.inner.clone().into(),
201 &[target.into(), start.into(), end.into_or_undefined()],
202 context,
203 )?;
204
205 Ok(Self {
206 inner: object
207 .as_object()
208 .js_expect("`copyWithin` must always return a `TypedArray` on success")?,
209 })
210 }
211
212 pub fn fill<T>(
214 &self,
215 value: T,
216 start: Option<usize>,
217 end: Option<usize>,
218 context: &mut Context,
219 ) -> JsResult<Self>
220 where
221 T: Into<JsValue>,
222 {
223 BuiltinTypedArray::fill(
224 &self.inner.clone().into(),
225 &[
226 value.into(),
227 start.into_or_undefined(),
228 end.into_or_undefined(),
229 ],
230 context,
231 )?;
232 Ok(self.clone())
233 }
234
235 pub fn every(
237 &self,
238 predicate: JsFunction,
239 this_arg: Option<JsValue>,
240 context: &mut Context,
241 ) -> JsResult<bool> {
242 let result = BuiltinTypedArray::every(
243 &self.inner.clone().into(),
244 &[predicate.into(), this_arg.into_or_undefined()],
245 context,
246 )?
247 .as_boolean()
248 .js_expect("TypedArray.prototype.every should always return boolean")?;
249
250 Ok(result)
251 }
252
253 #[inline]
255 pub fn some(
256 &self,
257 callback: JsFunction,
258 this_arg: Option<JsValue>,
259 context: &mut Context,
260 ) -> JsResult<bool> {
261 let result = BuiltinTypedArray::some(
262 &self.inner.clone().into(),
263 &[callback.into(), this_arg.into_or_undefined()],
264 context,
265 )?
266 .as_boolean()
267 .js_expect("TypedArray.prototype.some should always return boolean")?;
268
269 Ok(result)
270 }
271
272 #[inline]
274 pub fn sort(&self, compare_fn: Option<JsFunction>, context: &mut Context) -> JsResult<Self> {
275 BuiltinTypedArray::sort(
276 &self.inner.clone().into(),
277 &[compare_fn.into_or_undefined()],
278 context,
279 )?;
280
281 Ok(self.clone())
282 }
283
284 #[inline]
313 pub fn subarray(&self, begin: i64, end: i64, context: &mut Context) -> JsResult<Self> {
314 let subarray = BuiltinTypedArray::subarray(
315 &self.inner.clone().into(),
316 &[begin.into(), end.into()],
317 context,
318 )?;
319
320 Ok(Self {
321 inner: subarray
322 .as_object()
323 .js_expect("`subarray` must always return a `TypedArray` on success")?,
324 })
325 }
326
327 #[inline]
329 pub fn to_locale_string(
330 &self,
331 reserved1: Option<JsValue>,
332 reserved2: Option<JsValue>,
333 context: &mut Context,
334 ) -> JsResult<JsValue> {
335 BuiltinTypedArray::to_locale_string(
336 &self.inner.clone().into(),
337 &[reserved1.into_or_undefined(), reserved2.into_or_undefined()],
338 context,
339 )
340 }
341
342 #[inline]
344 pub fn filter(
345 &self,
346 callback: JsFunction,
347 this_arg: Option<JsValue>,
348 context: &mut Context,
349 ) -> JsResult<Self> {
350 let object = BuiltinTypedArray::filter(
351 &self.inner.clone().into(),
352 &[callback.into(), this_arg.into_or_undefined()],
353 context,
354 )?;
355
356 Ok(Self {
357 inner: object
358 .as_object()
359 .js_expect("`filter` must always return a `TypedArray` on success")?,
360 })
361 }
362
363 #[inline]
365 pub fn map(
366 &self,
367 callback: JsFunction,
368 this_arg: Option<JsValue>,
369 context: &mut Context,
370 ) -> JsResult<Self> {
371 let object = BuiltinTypedArray::map(
372 &self.inner.clone().into(),
373 &[callback.into(), this_arg.into_or_undefined()],
374 context,
375 )?;
376
377 Ok(Self {
378 inner: object
379 .as_object()
380 .js_expect("`map` must always return a `TypedArray` on success")?,
381 })
382 }
383
384 #[inline]
386 pub fn reduce(
387 &self,
388 callback: JsFunction,
389 initial_value: Option<JsValue>,
390 context: &mut Context,
391 ) -> JsResult<JsValue> {
392 BuiltinTypedArray::reduce(
393 &self.inner.clone().into(),
394 &[callback.into(), initial_value.into_or_undefined()],
395 context,
396 )
397 }
398
399 #[inline]
401 pub fn reduce_right(
402 &self,
403 callback: JsFunction,
404 initial_value: Option<JsValue>,
405 context: &mut Context,
406 ) -> JsResult<JsValue> {
407 BuiltinTypedArray::reduceright(
408 &self.inner.clone().into(),
409 &[callback.into(), initial_value.into_or_undefined()],
410 context,
411 )
412 }
413
414 #[inline]
416 pub fn reverse(&self, context: &mut Context) -> JsResult<Self> {
417 BuiltinTypedArray::reverse(&self.inner.clone().into(), &[], context)?;
418 Ok(self.clone())
419 }
420
421 #[inline]
454 pub fn set_values(
455 &self,
456 source: JsValue,
457 offset: Option<u64>,
458 context: &mut Context,
459 ) -> JsResult<JsValue> {
460 BuiltinTypedArray::set(
461 &self.inner.clone().into(),
462 &[source, offset.into_or_undefined()],
463 context,
464 )
465 }
466
467 #[inline]
469 pub fn slice(
470 &self,
471 start: Option<usize>,
472 end: Option<usize>,
473 context: &mut Context,
474 ) -> JsResult<Self> {
475 let object = BuiltinTypedArray::slice(
476 &self.inner.clone().into(),
477 &[start.into_or_undefined(), end.into_or_undefined()],
478 context,
479 )?;
480
481 Ok(Self {
482 inner: object
483 .as_object()
484 .js_expect("`slice` must always return a `TypedArray` on success")?,
485 })
486 }
487
488 #[inline]
490 pub fn find(
491 &self,
492 predicate: JsFunction,
493 this_arg: Option<JsValue>,
494 context: &mut Context,
495 ) -> JsResult<JsValue> {
496 BuiltinTypedArray::find(
497 &self.inner.clone().into(),
498 &[predicate.into(), this_arg.into_or_undefined()],
499 context,
500 )
501 }
502
503 #[inline]
540 pub fn find_index(
541 &self,
542 predicate: JsFunction,
543 this_arg: Option<JsValue>,
544 context: &mut Context,
545 ) -> JsResult<Option<u64>> {
546 let index = BuiltinTypedArray::find_index(
547 &self.inner.clone().into(),
548 &[predicate.into(), this_arg.into_or_undefined()],
549 context,
550 )?
551 .as_number()
552 .js_expect("TypedArray.prototype.findIndex() should always return number")?;
553
554 if index >= 0.0 {
555 Ok(Some(index as u64))
556 } else {
557 Ok(None)
558 }
559 }
560
561 #[inline]
598 pub fn find_last(
599 &self,
600 predicate: JsFunction,
601 this_arg: Option<JsValue>,
602 context: &mut Context,
603 ) -> JsResult<JsValue> {
604 BuiltinTypedArray::find_last(
605 &self.inner.clone().into(),
606 &[predicate.into(), this_arg.into_or_undefined()],
607 context,
608 )
609 }
610
611 #[inline]
648 pub fn find_last_index(
649 &self,
650 predicate: JsFunction,
651 this_arg: Option<JsValue>,
652 context: &mut Context,
653 ) -> JsResult<Option<u64>> {
654 let index = BuiltinTypedArray::find_last_index(
655 &self.inner.clone().into(),
656 &[predicate.into(), this_arg.into_or_undefined()],
657 context,
658 )?
659 .as_number()
660 .js_expect("TypedArray.prototype.findLastIndex() should always return number")?;
661
662 if index >= 0.0 {
663 Ok(Some(index as u64))
664 } else {
665 Ok(None)
666 }
667 }
668
669 #[inline]
709 pub fn for_each(
710 &self,
711 callback: JsFunction,
712 this_arg: Option<JsValue>,
713 context: &mut Context,
714 ) -> JsResult<JsValue> {
715 BuiltinTypedArray::for_each(
716 &self.inner.clone().into(),
717 &[callback.into(), this_arg.into_or_undefined()],
718 context,
719 )
720 }
721
722 #[inline]
748 pub fn includes<T>(
749 &self,
750 search_element: T,
751 from_index: Option<u64>,
752 context: &mut Context,
753 ) -> JsResult<bool>
754 where
755 T: Into<JsValue>,
756 {
757 let result = BuiltinTypedArray::includes(
758 &self.inner.clone().into(),
759 &[search_element.into(), from_index.into_or_undefined()],
760 context,
761 )?
762 .as_boolean()
763 .js_expect("TypedArray.prototype.includes should always return boolean")?;
764
765 Ok(result)
766 }
767
768 pub fn index_of<T>(
770 &self,
771 search_element: T,
772 from_index: Option<usize>,
773 context: &mut Context,
774 ) -> JsResult<Option<usize>>
775 where
776 T: Into<JsValue>,
777 {
778 let index = BuiltinTypedArray::index_of(
779 &self.inner.clone().into(),
780 &[search_element.into(), from_index.into_or_undefined()],
781 context,
782 )?
783 .as_number()
784 .js_expect("TypedArray.prototype.indexOf should always return number")?;
785
786 #[allow(clippy::float_cmp)]
787 if index == -1.0 {
788 Ok(None)
789 } else {
790 Ok(Some(index as usize))
791 }
792 }
793
794 pub fn last_index_of<T>(
796 &self,
797 search_element: T,
798 from_index: Option<usize>,
799 context: &mut Context,
800 ) -> JsResult<Option<usize>>
801 where
802 T: Into<JsValue>,
803 {
804 let index = BuiltinTypedArray::last_index_of(
805 &self.inner.clone().into(),
806 &[search_element.into(), from_index.into_or_undefined()],
807 context,
808 )?
809 .as_number()
810 .js_expect("TypedArray.prototype.lastIndexOf should always return number")?;
811
812 #[allow(clippy::float_cmp)]
813 if index == -1.0 {
814 Ok(None)
815 } else {
816 Ok(Some(index as usize))
817 }
818 }
819
820 #[inline]
822 pub fn join(&self, separator: Option<JsString>, context: &mut Context) -> JsResult<JsString> {
823 BuiltinTypedArray::join(
824 &self.inner.clone().into(),
825 &[separator.into_or_undefined()],
826 context,
827 )
828 .and_then(|x| {
829 x.as_string()
830 .js_expect("TypedArray.prototype.join always returns string")
831 .map_err(Into::into)
832 })
833 }
834
835 #[inline]
837 pub fn to_reversed(&self, context: &mut Context) -> JsResult<Self> {
838 let array = BuiltinTypedArray::to_reversed(&self.inner.clone().into(), &[], context)?;
839
840 Ok(Self {
841 inner: array
842 .as_object()
843 .js_expect("`to_reversed` must always return a `TypedArray` on success")?,
844 })
845 }
846
847 #[inline]
849 pub fn to_sorted(
850 &self,
851 compare_fn: Option<JsFunction>,
852 context: &mut Context,
853 ) -> JsResult<Self> {
854 let array = BuiltinTypedArray::to_sorted(
855 &self.inner.clone().into(),
856 &[compare_fn.into_or_undefined()],
857 context,
858 )?;
859
860 Ok(Self {
861 inner: array
862 .as_object()
863 .js_expect("`to_sorted` must always return a `TypedArray` on success")?,
864 })
865 }
866
867 #[inline]
869 pub fn with(&self, index: u64, value: JsValue, context: &mut Context) -> JsResult<Self> {
870 let array =
871 BuiltinTypedArray::with(&self.inner.clone().into(), &[index.into(), value], context)?;
872
873 Ok(Self {
874 inner: array
875 .as_object()
876 .js_expect("`with` must always return a `TypedArray` on success")?,
877 })
878 }
879
880 #[inline]
882 pub fn entries(&self, context: &mut Context) -> JsResult<JsValue> {
883 BuiltinTypedArray::entries(&self.inner.clone().into(), &[], context)
884 }
885
886 #[inline]
888 pub fn keys(&self, context: &mut Context) -> JsResult<JsValue> {
889 BuiltinTypedArray::keys(&self.inner.clone().into(), &[], context)
890 }
891
892 #[inline]
894 pub fn values(&self, context: &mut Context) -> JsResult<JsValue> {
895 BuiltinTypedArray::values(&self.inner.clone().into(), &[], context)
896 }
897
898 #[inline]
900 pub fn iterator(&self, context: &mut Context) -> JsResult<JsValue> {
901 BuiltinTypedArray::values(&self.inner.clone().into(), &[], context)
902 }
903
904 #[inline]
906 pub fn to_string(&self, context: &mut Context) -> JsResult<JsString> {
907 let result = crate::builtins::Array::to_string(&self.inner.clone().into(), &[], context)?;
909 result
910 .as_string()
911 .js_expect("Array.prototype.toString always returns string")
912 .map_err(Into::into)
913 }
914
915 #[inline]
935 pub fn to_string_tag(&self, context: &mut Context) -> JsResult<JsValue> {
936 BuiltinTypedArray::to_string_tag(&self.inner.clone().into(), &[], context)
937 }
938}
939
940impl From<JsTypedArray> for JsObject {
941 #[inline]
942 fn from(o: JsTypedArray) -> Self {
943 o.inner.clone()
944 }
945}
946
947impl From<JsTypedArray> for JsValue {
948 #[inline]
949 fn from(o: JsTypedArray) -> Self {
950 o.inner.clone().into()
951 }
952}
953
954impl Deref for JsTypedArray {
955 type Target = JsObject;
956
957 #[inline]
958 fn deref(&self) -> &Self::Target {
959 &self.inner
960 }
961}
962
963impl TryFromJs for JsTypedArray {
964 fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
965 if let Some(o) = value.as_object() {
966 Self::from_object(o.clone())
967 } else {
968 Err(JsNativeError::typ()
969 .with_message("value is not a TypedArray object")
970 .into())
971 }
972 }
973}
974
975macro_rules! JsTypedArrayType {
976 (
977 $name:ident,
978 $constructor_function:ident,
979 $kind:expr,
980 $constructor_object:ident,
981 $value_to_elem:ident,
982 $element:ty
983 ) => {
984
985 #[doc = concat!(
986 "`", stringify!($name),
987 "` provides a wrapper for Boa's implementation of the ECMAScript `",
988 stringify!($constructor_function) ,"` builtin object."
989 )]
990 #[derive(Debug, Clone, Trace, Finalize)]
991 pub struct $name {
992 inner: JsTypedArray,
993 }
994
995 impl $name {
996 #[doc = concat!("Creates a `", stringify!($name),
997 "` using a [`JsObject`]. It will make sure that the object is of the correct kind."
998 )]
999 #[inline]
1000 pub fn from_object(object: JsObject) -> JsResult<Self> {
1001 let is_kind = if let Some(int) = object.downcast_ref::<TypedArray>() {
1002 int.kind() == $kind
1003 } else {
1004 false
1005 };
1006 if is_kind {
1007 Ok(Self {
1008 inner: JsTypedArray {
1009 inner: object.into(),
1010 },
1011 })
1012 } else {
1013 Err(JsNativeError::typ()
1014 .with_message("object is not a TypedArray")
1015 .into())
1016 }
1017 }
1018
1019 pub fn from_array_buffer(
1021 array_buffer: JsArrayBuffer,
1022 context: &mut Context,
1023 ) -> JsResult<Self> {
1024 let new_target = context
1025 .intrinsics()
1026 .constructors()
1027 .$constructor_object()
1028 .constructor()
1029 .into();
1030 let object = crate::builtins::typed_array::$constructor_function::constructor(
1031 &new_target,
1032 &[array_buffer.into()],
1033 context,
1034 )?
1035 .as_object()
1036 .js_expect("object")?
1037 .clone();
1038
1039 Ok(Self {
1040 inner: JsTypedArray {
1041 inner: object.into(),
1042 },
1043 })
1044 }
1045
1046 pub fn from_shared_array_buffer(
1048 buffer: JsSharedArrayBuffer,
1049 context: &mut Context,
1050 ) -> JsResult<Self> {
1051 let new_target = context
1052 .intrinsics()
1053 .constructors()
1054 .$constructor_object()
1055 .constructor()
1056 .into();
1057 let object = crate::builtins::typed_array::$constructor_function::constructor(
1058 &new_target,
1059 &[buffer.into()],
1060 context,
1061 )?
1062 .as_object()
1063 .js_expect("object")?
1064 .clone();
1065
1066 Ok(Self {
1067 inner: JsTypedArray {
1068 inner: object.into(),
1069 },
1070 })
1071 }
1072
1073 pub fn from_iter<I>(elements: I, context: &mut Context) -> JsResult<Self>
1075 where
1076 I: IntoIterator<Item = $element>,
1077 {
1078 let bytes = AlignedVec::from_iter(
1079 0,
1080 elements
1081 .into_iter()
1082 .flat_map(<$element>::to_ne_bytes)
1083 );
1084 let array_buffer = JsArrayBuffer::from_byte_block(bytes, context)?;
1085 let new_target = context
1086 .intrinsics()
1087 .constructors()
1088 .$constructor_object()
1089 .constructor()
1090 .into();
1091 let object = crate::builtins::typed_array::$constructor_function::constructor(
1092 &new_target,
1093 &[array_buffer.into()],
1094 context,
1095 )?
1096 .as_object()
1097 .js_expect("object")?
1098 .clone();
1099
1100 Ok(Self {
1101 inner: JsTypedArray {
1102 inner: object.into(),
1103 },
1104 })
1105 }
1106
1107 pub fn iter<'a>(&'a self, context: &'a mut Context) -> impl Iterator<Item = $element> + 'a {
1109 let length = self.length(context).unwrap_or(0);
1110 let mut index = 0;
1111 std::iter::from_fn(move || {
1112 if index < length {
1113 let value = self.get(index, context).ok()?;
1114 index += 1;
1115 value.$value_to_elem(context).ok()
1116 } else {
1117 None
1118 }
1119 })
1120 }
1121 }
1122
1123 impl From<$name> for JsObject {
1124 #[inline]
1125 fn from(o: $name) -> Self {
1126 o.inner
1127 .inner
1128 .clone()
1129 }
1130 }
1131
1132 impl From<$name> for JsValue {
1133 #[inline]
1134 fn from(o: $name) -> Self {
1135 o.inner.inner.clone().into()
1136 }
1137 }
1138
1139 impl Deref for $name {
1140 type Target = JsTypedArray;
1141
1142 #[inline]
1143 fn deref(&self) -> &Self::Target {
1144 &self.inner
1145 }
1146 }
1147
1148 impl TryFromJs for $name {
1149 fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
1150 if let Some(o) = value.as_object() {
1151 Self::from_object(o.clone())
1152 } else {
1153 Err(JsNativeError::typ()
1154 .with_message(concat!(
1155 "value is not a ",
1156 stringify!($constructor_function),
1157 " object"
1158 ))
1159 .into())
1160 }
1161 }
1162 }
1163 };
1164}
1165
1166JsTypedArrayType!(
1167 JsUint8Array,
1168 Uint8Array,
1169 TypedArrayKind::Uint8,
1170 typed_uint8_array,
1171 to_uint8,
1172 u8
1173);
1174
1175impl JsUint8Array {
1176 #[inline]
1197 pub fn to_vec(&self, _context: &mut Context) -> JsResult<Vec<u8>> {
1198 let this_val = self.inner.inner.clone().into();
1199 let (obj, buf_byte_len) = TypedArray::validate(&this_val, Ordering::SeqCst)?;
1200 let vec = {
1201 let array = obj.borrow();
1202 let ta = array.data();
1203 let buffer = ta.viewed_array_buffer().as_buffer();
1204 let Some(slice) = buffer.bytes(Ordering::SeqCst) else {
1205 return Err(JsNativeError::typ()
1206 .with_message("typed array buffer is detached or out of bounds")
1207 .into());
1208 };
1209 if ta.is_out_of_bounds(slice.len()) {
1210 return Err(JsNativeError::typ()
1211 .with_message("typed array is outside the bounds of its inner buffer")
1212 .into());
1213 }
1214 let byte_offset = ta.byte_offset() as usize;
1215 let byte_len = ta.byte_length(buf_byte_len) as usize;
1216 slice.subslice(byte_offset..byte_offset + byte_len).to_vec()
1217 };
1218 Ok(vec)
1219 }
1220}
1221
1222JsTypedArrayType!(
1223 JsUint8ClampedArray,
1224 Uint8ClampedArray,
1225 TypedArrayKind::Uint8Clamped,
1226 typed_uint8clamped_array,
1227 to_uint8_clamp,
1228 u8
1229);
1230JsTypedArrayType!(
1231 JsInt8Array,
1232 Int8Array,
1233 TypedArrayKind::Int8,
1234 typed_int8_array,
1235 to_int8,
1236 i8
1237);
1238JsTypedArrayType!(
1239 JsUint16Array,
1240 Uint16Array,
1241 TypedArrayKind::Uint16,
1242 typed_uint16_array,
1243 to_uint16,
1244 u16
1245);
1246JsTypedArrayType!(
1247 JsInt16Array,
1248 Int16Array,
1249 TypedArrayKind::Int16,
1250 typed_int16_array,
1251 to_int16,
1252 i16
1253);
1254JsTypedArrayType!(
1255 JsUint32Array,
1256 Uint32Array,
1257 TypedArrayKind::Uint32,
1258 typed_uint32_array,
1259 to_u32,
1260 u32
1261);
1262JsTypedArrayType!(
1263 JsInt32Array,
1264 Int32Array,
1265 TypedArrayKind::Int32,
1266 typed_int32_array,
1267 to_i32,
1268 i32
1269);
1270#[cfg(feature = "float16")]
1271JsTypedArrayType!(
1272 JsFloat16Array,
1273 Float16Array,
1274 TypedArrayKind::Float16,
1275 typed_float16_array,
1276 to_f16,
1277 float16::f16
1278);
1279JsTypedArrayType!(
1280 JsBigInt64Array,
1281 BigInt64Array,
1282 TypedArrayKind::BigInt64,
1283 typed_bigint64_array,
1284 to_big_int64,
1285 i64
1286);
1287JsTypedArrayType!(
1288 JsBigUint64Array,
1289 BigUint64Array,
1290 TypedArrayKind::BigUint64,
1291 typed_biguint64_array,
1292 to_big_uint64,
1293 u64
1294);
1295JsTypedArrayType!(
1296 JsFloat32Array,
1297 Float32Array,
1298 TypedArrayKind::Float32,
1299 typed_float32_array,
1300 to_f32,
1301 f32
1302);
1303JsTypedArrayType!(
1304 JsFloat64Array,
1305 Float64Array,
1306 TypedArrayKind::Float64,
1307 typed_float64_array,
1308 to_number,
1309 f64
1310);
1311
1312#[inline]
1314pub fn js_typed_array_from_kind(
1315 kind: TypedArrayKind,
1316 inner: JsArrayBuffer,
1317 context: &mut Context,
1318) -> JsResult<JsValue> {
1319 match kind {
1320 TypedArrayKind::Int8 => JsInt8Array::from_array_buffer(inner, context).map(Into::into),
1321 TypedArrayKind::Uint8 => JsUint8Array::from_array_buffer(inner, context).map(Into::into),
1322 TypedArrayKind::Uint8Clamped => {
1323 JsUint8ClampedArray::from_array_buffer(inner, context).map(Into::into)
1324 }
1325 TypedArrayKind::Int16 => JsInt16Array::from_array_buffer(inner, context).map(Into::into),
1326 TypedArrayKind::Uint16 => JsUint16Array::from_array_buffer(inner, context).map(Into::into),
1327 TypedArrayKind::Int32 => JsInt32Array::from_array_buffer(inner, context).map(Into::into),
1328 TypedArrayKind::Uint32 => JsUint32Array::from_array_buffer(inner, context).map(Into::into),
1329 TypedArrayKind::BigInt64 => {
1330 JsBigInt64Array::from_array_buffer(inner, context).map(Into::into)
1331 }
1332 TypedArrayKind::BigUint64 => {
1333 JsBigUint64Array::from_array_buffer(inner, context).map(Into::into)
1334 }
1335 #[cfg(feature = "float16")]
1336 TypedArrayKind::Float16 => {
1337 JsFloat16Array::from_array_buffer(inner, context).map(Into::into)
1338 }
1339 TypedArrayKind::Float32 => {
1340 JsFloat32Array::from_array_buffer(inner, context).map(Into::into)
1341 }
1342 TypedArrayKind::Float64 => {
1343 JsFloat64Array::from_array_buffer(inner, context).map(Into::into)
1344 }
1345 }
1346}
1347
1348#[test]
1349fn typed_iterators_uint8() {
1350 let context = &mut Context::default();
1351 let vec = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
1352
1353 let array = JsUint8Array::from_iter(vec.clone(), context).unwrap();
1354 let vec2 = array.iter(context).collect::<Vec<_>>();
1355 assert_eq!(vec, vec2);
1356}
1357
1358#[test]
1359fn uint8_array_to_vec_roundtrip() {
1360 let context = &mut Context::default();
1361 let data: Vec<u8> = (0..=255).collect();
1362 let array = JsUint8Array::from_iter(data.clone(), context).unwrap();
1363 let bytes = array.to_vec(context).unwrap();
1364 assert_eq!(bytes, data);
1365}
1366
1367#[test]
1368fn typed_iterators_uint32() {
1369 let context = &mut Context::default();
1370 let vec = vec![1u32, 2, 0xFFFF, 4, 0xFF12_3456, 6, 7, 8];
1371
1372 let array = JsUint32Array::from_iter(vec.clone(), context).unwrap();
1373 let vec2 = array.iter(context).collect::<Vec<_>>();
1374 assert_eq!(vec, vec2);
1375}
1376
1377#[test]
1378fn typed_iterators_f32() {
1379 let context = &mut Context::default();
1380 let vec = vec![0.1f32, 0.2, 0.3, 0.4, 1.1, 9.99999];
1381
1382 let array = JsFloat32Array::from_iter(vec.clone(), context).unwrap();
1383 let vec2 = array.iter(context).collect::<Vec<_>>();
1384 assert_eq!(vec, vec2);
1385}
1386
1387#[test]
1388fn typed_array_to_string() {
1389 let context = &mut Context::default();
1390 let vec = vec![1u8, 2, 3];
1391 let array = JsUint8Array::from_iter(vec, context).unwrap();
1392 assert_eq!(
1393 array.to_string(context).unwrap(),
1394 crate::js_string!("1,2,3")
1395 );
1396}
1397
1398#[test]
1399fn typed_array_entries() {
1400 let context = &mut Context::default();
1401 let vec = vec![1u8, 2];
1402 let array = JsUint8Array::from_iter(vec, context).unwrap();
1403 let entries = array.entries(context).unwrap();
1404 let mut entries_vec = Vec::new();
1405 let next_str = crate::js_string!("next");
1406 loop {
1407 let next_fn = entries
1408 .as_object()
1409 .unwrap()
1410 .get(next_str.clone(), context)
1411 .unwrap();
1412 let result = next_fn
1413 .as_object()
1414 .unwrap()
1415 .call(&entries, &[], context)
1416 .unwrap();
1417 if result
1418 .as_object()
1419 .unwrap()
1420 .get(crate::js_string!("done"), context)
1421 .unwrap()
1422 .to_boolean()
1423 {
1424 break;
1425 }
1426 entries_vec.push(
1427 result
1428 .as_object()
1429 .unwrap()
1430 .get(crate::js_string!("value"), context)
1431 .unwrap(),
1432 );
1433 }
1434 assert_eq!(entries_vec.len(), 2);
1435}
1436
1437#[test]
1438fn typed_array_keys() {
1439 let context = &mut Context::default();
1440 let vec = vec![1u8, 2];
1441 let array = JsUint8Array::from_iter(vec, context).unwrap();
1442 let keys = array.keys(context).unwrap();
1443 let mut keys_vec = Vec::new();
1444 let next_str = crate::js_string!("next");
1445 loop {
1446 let next_fn = keys
1447 .as_object()
1448 .unwrap()
1449 .get(next_str.clone(), context)
1450 .unwrap();
1451 let result = next_fn
1452 .as_object()
1453 .unwrap()
1454 .call(&keys, &[], context)
1455 .unwrap();
1456 if result
1457 .as_object()
1458 .unwrap()
1459 .get(crate::js_string!("done"), context)
1460 .unwrap()
1461 .to_boolean()
1462 {
1463 break;
1464 }
1465 keys_vec.push(
1466 result
1467 .as_object()
1468 .unwrap()
1469 .get(crate::js_string!("value"), context)
1470 .unwrap(),
1471 );
1472 }
1473 assert_eq!(keys_vec, vec![JsValue::new(0), JsValue::new(1)]);
1474}
1475
1476#[test]
1477fn typed_array_values() {
1478 let context = &mut Context::default();
1479 let vec = vec![1u8, 2];
1480 let array = JsUint8Array::from_iter(vec, context).unwrap();
1481 let values = array.values(context).unwrap();
1482 let mut values_vec = Vec::new();
1483 let next_str = crate::js_string!("next");
1484 loop {
1485 let next_fn = values
1486 .as_object()
1487 .unwrap()
1488 .get(next_str.clone(), context)
1489 .unwrap();
1490 let result = next_fn
1491 .as_object()
1492 .unwrap()
1493 .call(&values, &[], context)
1494 .unwrap();
1495 if result
1496 .as_object()
1497 .unwrap()
1498 .get(crate::js_string!("done"), context)
1499 .unwrap()
1500 .to_boolean()
1501 {
1502 break;
1503 }
1504 values_vec.push(
1505 result
1506 .as_object()
1507 .unwrap()
1508 .get(crate::js_string!("value"), context)
1509 .unwrap(),
1510 );
1511 }
1512 assert_eq!(values_vec, vec![JsValue::new(1), JsValue::new(2)]);
1513}
1514
1515#[test]
1516fn typed_array_iterator() {
1517 let context = &mut Context::default();
1518 let array = JsUint8Array::from_iter(vec![1u8, 2], context).unwrap();
1519 let values = array.iterator(context).unwrap();
1520 let mut values_vec = Vec::new();
1521 let next_str = crate::js_string!("next");
1522 loop {
1523 let next_fn = values
1524 .as_object()
1525 .unwrap()
1526 .get(next_str.clone(), context)
1527 .unwrap();
1528 let result = next_fn
1529 .as_object()
1530 .unwrap()
1531 .call(&values, &[], context)
1532 .unwrap();
1533 if result
1534 .as_object()
1535 .unwrap()
1536 .get(crate::js_string!("done"), context)
1537 .unwrap()
1538 .to_boolean()
1539 {
1540 break;
1541 }
1542 values_vec.push(
1543 result
1544 .as_object()
1545 .unwrap()
1546 .get(crate::js_string!("value"), context)
1547 .unwrap(),
1548 );
1549 }
1550 assert_eq!(values_vec, vec![JsValue::new(1), JsValue::new(2)]);
1551}
1552
1553#[test]
1554fn typed_array_to_reversed() {
1555 let context = &mut Context::default();
1556 let array = JsUint8Array::from_iter(vec![3u8, 1, 2], context).unwrap();
1557
1558 let reversed = array.to_reversed(context).unwrap();
1559
1560 assert_eq!(reversed.at(0i64, context).unwrap(), JsValue::new(2));
1562 assert_eq!(reversed.at(1i64, context).unwrap(), JsValue::new(1));
1563 assert_eq!(reversed.at(2i64, context).unwrap(), JsValue::new(3));
1564
1565 assert_eq!(array.at(0i64, context).unwrap(), JsValue::new(3));
1567 assert_eq!(array.at(1i64, context).unwrap(), JsValue::new(1));
1568 assert_eq!(array.at(2i64, context).unwrap(), JsValue::new(2));
1569}
1570
1571#[test]
1572fn typed_array_to_sorted() {
1573 let context = &mut Context::default();
1574 let array = JsUint8Array::from_iter(vec![3u8, 1, 2], context).unwrap();
1575
1576 let sorted = array.to_sorted(None, context).unwrap();
1577
1578 assert_eq!(sorted.at(0i64, context).unwrap(), JsValue::new(1));
1580 assert_eq!(sorted.at(1i64, context).unwrap(), JsValue::new(2));
1581 assert_eq!(sorted.at(2i64, context).unwrap(), JsValue::new(3));
1582
1583 assert_eq!(array.at(0i64, context).unwrap(), JsValue::new(3));
1585 assert_eq!(array.at(1i64, context).unwrap(), JsValue::new(1));
1586 assert_eq!(array.at(2i64, context).unwrap(), JsValue::new(2));
1587}
1588
1589#[test]
1590fn typed_array_to_locale_string() {
1591 let context = &mut Context::default();
1592 let array = JsUint8Array::from_iter(vec![1u8, 2, 3], context).unwrap();
1593
1594 let result = array.to_locale_string(None, None, context).unwrap();
1595
1596 let result_str = result
1597 .as_string()
1598 .expect("toLocaleString should return a string");
1599 assert!(
1600 result_str.to_std_string_escaped().contains('1'),
1601 "result should contain element values"
1602 );
1603}