1mod install;
16pub(super) mod sort;
17
18pub(crate) use install::{array_like_type, declare_types};
19pub use install::{declare, install};
20pub(crate) use sort::merge_sort;
21
22use wasmtime::{Caller, StructRef, StructRefPre, Val};
23
24use crate::runtime::StoreData;
25use crate::runtime::array_storage::ArrayStorage;
26use crate::runtime::host::{host_boxed_number_vtable, write_submilli_array_struct};
27use crate::runtime::intrinsic_types::intrinsic_types;
28use crate::runtime::prelude::closure::Closure;
29use crate::runtime::prelude::collection::both_nan;
30use crate::runtime::prelude::iterator::{IterKind, make_index_iterator};
31use crate::runtime::prelude::keep::{KeptValue, KeptValues, keep_all};
32use crate::runtime::prelude::vtable::{dispatch_vtable_slot, read_string_units};
33
34pub(super) fn read_array(
41 caller: &mut Caller<'_, StoreData>,
42 val: &Val,
43 _name: &str,
44) -> wasmtime::Result<Vec<Val>> {
45 crate::runtime::array_storage::ArrayStorage::read(caller, val)?.snapshot(caller)
46}
47
48pub(super) fn read_kept_array(
54 caller: &mut Caller<'_, StoreData>,
55 val: &Val,
56 name: &str,
57) -> wasmtime::Result<Vec<Val>> {
58 let elements = read_array(caller, val, name)?;
59 keep_all(caller, &elements)?;
60 Ok(elements)
61}
62
63fn build_array(caller: &mut Caller<'_, StoreData>, elements: &[Val]) -> wasmtime::Result<Val> {
65 let st = write_submilli_array_struct(caller, elements)?;
66 Ok(Val::AnyRef(Some(st.to_anyref())))
67}
68
69fn replace_elements(
71 caller: &mut Caller<'_, StoreData>,
72 receiver: &Val,
73 elements: &[Val],
74) -> wasmtime::Result<()> {
75 crate::runtime::array_storage::ArrayStorage::read(caller, receiver)?.replace(caller, elements)
76}
77
78fn box_number(caller: &mut Caller<'_, StoreData>, n: f64) -> wasmtime::Result<Val> {
80 let boxed = intrinsic_types(&mut *caller)?.boxed_number.clone();
81 let vtable = host_boxed_number_vtable(caller)?;
82 let pre = StructRefPre::new(&mut *caller, boxed);
83 let st = StructRef::new(&mut *caller, &pre, &[vtable, Val::F64(n.to_bits())])?;
84 Ok(Val::AnyRef(Some(st.to_anyref())))
85}
86
87pub(super) fn is_array(caller: &mut Caller<'_, StoreData>, val: &Val) -> wasmtime::Result<bool> {
89 let Val::AnyRef(Some(any)) = val else {
90 return Ok(false);
91 };
92 let Some(st) = any.as_struct(&mut *caller)? else {
93 return Ok(false);
94 };
95 let array_ty = intrinsic_types(&mut *caller)?.array.clone();
96 st.matches_ty(&*caller, &array_ty)
97}
98
99fn is_null(v: &Val) -> bool {
100 matches!(v, Val::AnyRef(None))
101}
102
103async fn element_to_string(
107 caller: &mut Caller<'_, StoreData>,
108 elem: Val,
109) -> wasmtime::Result<Vec<u16>> {
110 if is_null(&elem) {
111 return Err(wasmtime::Error::msg("array element toString: null element"));
112 }
113 let s = dispatch_vtable_slot(caller, &elem, 0, &[]).await?;
114 read_string_units(caller, &s, "array element toString result")
115}
116
117async fn join_text(caller: &mut Caller<'_, StoreData>, elem: Val) -> wasmtime::Result<Vec<u16>> {
120 if super::undefined::is_nullish(caller, &elem)? {
121 return Ok(Vec::new());
122 }
123 element_to_string(caller, elem).await
124}
125
126async fn element_matches(
130 caller: &mut Caller<'_, StoreData>,
131 slot: Val,
132 target: Val,
133) -> wasmtime::Result<bool> {
134 if is_null(&slot) || is_null(&target) {
135 return Ok(is_null(&slot) && is_null(&target));
136 }
137 let left_undefined = super::undefined::is_undefined(caller, &slot)?;
138 let right_undefined = super::undefined::is_undefined(caller, &target)?;
139 if left_undefined || right_undefined {
140 return Ok(left_undefined && right_undefined);
141 }
142 element_equals(caller, slot, target).await
143}
144
145async fn element_equals(
147 caller: &mut Caller<'_, StoreData>,
148 slot: Val,
149 target: Val,
150) -> wasmtime::Result<bool> {
151 match dispatch_vtable_slot(caller, &slot, 2, &[target]).await? {
152 Val::I32(b) => Ok(b != 0),
153 other => Err(wasmtime::Error::msg(format!(
154 "array element equals returned {other:?}, expected i32"
155 ))),
156 }
157}
158
159fn trunc_sat(x: f64) -> i32 {
165 x as i32
166}
167
168fn norm_clamp(x: f64, len: i32) -> i32 {
170 let mut i = trunc_sat(x);
171 if i < 0 {
172 i += len;
173 }
174 i.clamp(0, len)
175}
176
177fn at_index(x: f64, len: i32) -> Option<usize> {
179 let mut i = trunc_sat(x);
180 if i < 0 {
181 i += len;
182 }
183 if i < 0 || i >= len {
184 None
185 } else {
186 Some(i as usize)
187 }
188}
189
190fn fwd_from(x: f64, len: i32) -> i32 {
192 let mut fi = trunc_sat(x);
193 if fi < 0 {
194 fi += len;
195 }
196 fi.max(0)
197}
198
199fn last_from(x: f64, len: i32) -> Option<i32> {
202 let mut fi = trunc_sat(x);
203 if fi < 0 {
204 fi += len;
205 }
206 if fi < 0 {
207 return None;
208 }
209 Some(fi.min(len - 1))
210}
211
212fn at(caller: &mut Caller<'_, StoreData>, receiver: &Val, index: f64) -> wasmtime::Result<Val> {
218 let storage = ArrayStorage::read(caller, receiver)?;
219 match at_index(index, storage.len as i32) {
220 Some(i) => storage.get(caller, i as u32),
221 None => super::undefined::value(caller),
222 }
223}
224
225fn slice(
227 caller: &mut Caller<'_, StoreData>,
228 receiver: &Val,
229 start: f64,
230 end: f64,
231) -> wasmtime::Result<Vec<Val>> {
232 let storage = ArrayStorage::read(caller, receiver)?;
233 let len = storage.len as i32;
234 let si = norm_clamp(start, len);
235 let count = (norm_clamp(end, len) - si).max(0);
236 storage.range(caller, si as u32, count as u32)
237}
238
239fn concat(
242 caller: &mut Caller<'_, StoreData>,
243 mut acc: Vec<Val>,
244 others: &Val,
245) -> wasmtime::Result<Vec<Val>> {
246 for sub in read_array(caller, others, "Array#concat")? {
247 acc.extend(read_array(caller, &sub, "Array#concat")?);
248 }
249 Ok(acc)
250}
251
252async fn index_of(
253 caller: &mut Caller<'_, StoreData>,
254 elements: Vec<Val>,
255 target: Val,
256 from: f64,
257) -> wasmtime::Result<f64> {
258 let len = elements.len() as i32;
259 let mut i = fwd_from(from, len);
260 while i < len {
261 let e = elements[i as usize];
262 if element_matches(caller, e, target).await? {
263 return Ok(i as f64);
264 }
265 i += 1;
266 }
267 Ok(-1.0)
268}
269
270async fn last_index_of(
271 caller: &mut Caller<'_, StoreData>,
272 elements: Vec<Val>,
273 target: Val,
274 from: f64,
275) -> wasmtime::Result<f64> {
276 let len = elements.len() as i32;
277 let Some(mut i) = last_from(from, len) else {
278 return Ok(-1.0);
279 };
280 while i >= 0 {
281 let e = elements[i as usize];
282 if element_matches(caller, e, target).await? {
283 return Ok(i as f64);
284 }
285 i -= 1;
286 }
287 Ok(-1.0)
288}
289
290async fn includes(
291 caller: &mut Caller<'_, StoreData>,
292 elements: Vec<Val>,
293 target: Val,
294 from: f64,
295) -> wasmtime::Result<bool> {
296 let len = elements.len() as i32;
297 let mut i = fwd_from(from, len);
298 while i < len {
299 let e = elements[i as usize];
300 if element_matches(caller, e, target).await? || both_nan(caller, &e, &target)? {
302 return Ok(true);
303 }
304 i += 1;
305 }
306 Ok(false)
307}
308
309async fn join(
310 caller: &mut Caller<'_, StoreData>,
311 elements: Vec<Val>,
312 sep: Vec<u16>,
313) -> wasmtime::Result<Vec<u16>> {
314 if elements.is_empty() {
315 return Ok(Vec::new());
316 }
317 let mut acc = join_text(caller, elements[0]).await?;
318 for &e in &elements[1..] {
319 acc.extend_from_slice(&sep);
320 let s = join_text(caller, e).await?;
321 acc.extend_from_slice(&s);
322 }
323 Ok(acc)
324}
325
326fn push(caller: &mut Caller<'_, StoreData>, receiver: &Val, elem: Val) -> wasmtime::Result<f64> {
331 crate::runtime::array_storage::ArrayStorage::read(caller, receiver)?.push(caller, elem)
332}
333
334fn pop(caller: &mut Caller<'_, StoreData>, receiver: &Val) -> wasmtime::Result<Val> {
336 let popped = ArrayStorage::read(caller, receiver)?.pop(caller)?;
337 match popped {
338 Some(value) => Ok(value),
339 None => super::undefined::value(caller),
340 }
341}
342
343fn shift(
344 caller: &mut Caller<'_, StoreData>,
345 receiver: &Val,
346 mut elements: Vec<Val>,
347) -> wasmtime::Result<Val> {
348 if elements.is_empty() {
349 return super::undefined::value(caller);
350 }
351 let first = elements.remove(0);
352 replace_elements(caller, receiver, &elements)?;
353 Ok(first)
354}
355
356fn unshift(
357 caller: &mut Caller<'_, StoreData>,
358 receiver: &Val,
359 elements: Vec<Val>,
360 mut items: Vec<Val>,
361) -> wasmtime::Result<f64> {
362 items.extend(elements);
363 let n = items.len() as f64;
364 replace_elements(caller, receiver, &items)?;
365 Ok(n)
366}
367
368fn reverse(
369 caller: &mut Caller<'_, StoreData>,
370 receiver: &Val,
371 mut elements: Vec<Val>,
372) -> wasmtime::Result<Val> {
373 elements.reverse();
374 replace_elements(caller, receiver, &elements)?;
375 Ok(*receiver)
376}
377
378fn fill(
379 caller: &mut Caller<'_, StoreData>,
380 receiver: &Val,
381 mut elements: Vec<Val>,
382 value: Val,
383 start: f64,
384 end: f64,
385) -> wasmtime::Result<Val> {
386 let len = elements.len() as i32;
387 let si = norm_clamp(start, len);
388 let ei = norm_clamp(end, len);
389 for slot in elements.iter_mut().take(ei as usize).skip(si as usize) {
390 *slot = value;
391 }
392 replace_elements(caller, receiver, &elements)?;
393 Ok(*receiver)
394}
395
396fn copy_within(
397 caller: &mut Caller<'_, StoreData>,
398 receiver: &Val,
399 mut elements: Vec<Val>,
400 target: f64,
401 start: f64,
402 end: f64,
403) -> wasmtime::Result<Val> {
404 let len = elements.len() as i32;
405 let ti = norm_clamp(target, len);
406 let si = norm_clamp(start, len);
407 let ei = norm_clamp(end, len);
408 let mut count = (ei - si).max(0);
409 let rem = len - ti;
410 if count > rem {
411 count = rem;
412 }
413 let src: Vec<Val> = elements[si as usize..(si + count) as usize].to_vec();
415 for (k, v) in src.into_iter().enumerate() {
416 elements[ti as usize + k] = v;
417 }
418 replace_elements(caller, receiver, &elements)?;
419 Ok(*receiver)
420}
421
422fn splice_parts(
425 elements: &[Val],
426 start: f64,
427 delete_count: f64,
428 items: Vec<Val>,
429) -> (Vec<Val>, Vec<Val>) {
430 let len = elements.len() as i32;
431 let si = norm_clamp(start, len);
432 let mut dc = trunc_sat(delete_count).max(0);
433 let rem = len - si;
434 if dc > rem {
435 dc = rem;
436 }
437 let (si, dc) = (si as usize, dc as usize);
438 let removed = elements[si..si + dc].to_vec();
439 let mut result = Vec::with_capacity(elements.len() - dc + items.len());
440 result.extend_from_slice(&elements[..si]);
441 result.extend(items);
442 result.extend_from_slice(&elements[si + dc..]);
443 (removed, result)
444}
445
446fn splice(
447 caller: &mut Caller<'_, StoreData>,
448 receiver: &Val,
449 elements: Vec<Val>,
450 start: f64,
451 delete_count: f64,
452 items: Vec<Val>,
453) -> wasmtime::Result<Val> {
454 let (removed, result) = splice_parts(&elements, start, delete_count, items);
455 let removed = build_array(caller, &removed)?;
458 replace_elements(caller, receiver, &result)?;
459 Ok(removed)
460}
461
462async fn sort(
463 caller: &mut Caller<'_, StoreData>,
464 receiver: &Val,
465 mut elements: Vec<Val>,
466 cmp: Option<Closure>,
467) -> wasmtime::Result<Val> {
468 sort_elems(caller, &mut elements, cmp.as_ref()).await?;
469 ArrayStorage::read(caller, receiver)?.overwrite_prefix(caller, &elements)?;
471 Ok(*receiver)
472}
473
474fn to_reversed(mut elements: Vec<Val>) -> Vec<Val> {
479 elements.reverse();
480 elements
481}
482
483async fn to_sorted(
484 caller: &mut Caller<'_, StoreData>,
485 mut elements: Vec<Val>,
486 cmp: Option<Closure>,
487) -> wasmtime::Result<Vec<Val>> {
488 sort_elems(caller, &mut elements, cmp.as_ref()).await?;
489 Ok(elements)
490}
491
492async fn sort_elems(
495 caller: &mut Caller<'_, StoreData>,
496 elements: &mut Vec<Val>,
497 cmp: Option<&Closure>,
498) -> wasmtime::Result<()> {
499 let original_len = elements.len();
500 let mut defined_len = 0usize;
501 for index in 0..original_len {
502 let element = *elements
503 .get(index)
504 .ok_or_else(|| crate::runtime::host::fatal_host_error("sort: invalid element index"))?;
505 if !super::undefined::is_undefined(caller, &element)? {
506 let slot = elements.get_mut(defined_len).ok_or_else(|| {
507 crate::runtime::host::fatal_host_error("sort: invalid output index")
508 })?;
509 *slot = element;
510 defined_len += 1;
511 }
512 }
513 elements.truncate(defined_len);
514 match cmp {
515 Some(cmp) => merge_sort(caller, elements, cmp, |_, element| Ok(element)).await?,
516 None => sort::sort_by_string(caller, elements).await?,
517 }
518 if defined_len != original_len {
519 let undefined = super::undefined::value(caller)?;
520 elements
521 .try_reserve_exact(original_len - defined_len)
522 .map_err(crate::runtime::host::fatal_host_error)?;
523 elements.resize(original_len, undefined);
524 }
525 Ok(())
526}
527
528fn with(elements: &[Val], index: f64, value: Val) -> Option<Vec<Val>> {
531 let i = at_index(index, elements.len() as i32)?;
532 let mut new = elements.to_vec();
533 new[i] = value;
534 Some(new)
535}
536
537pub(in crate::runtime::prelude) struct ElementCallback<'a> {
546 f: &'a Closure,
547 reads: usize,
548 array: Option<Val>,
549}
550
551impl<'a> ElementCallback<'a> {
552 pub(in crate::runtime::prelude) fn new(
553 caller: &mut Caller<'_, StoreData>,
554 f: &'a Closure,
555 array: Option<Val>,
556 ) -> wasmtime::Result<Self> {
557 let reads = f.arguments_read(caller)?;
558 Ok(Self { f, reads, array })
559 }
560
561 pub(in crate::runtime::prelude) async fn call(
563 &self,
564 caller: &mut Caller<'_, StoreData>,
565 leading: Option<Val>,
566 value: Val,
567 index: usize,
568 ) -> wasmtime::Result<Val> {
569 let mut args: Vec<Val> = leading.into_iter().chain([value]).collect();
570 if args.len() < self.reads {
571 args.push(box_number(caller, index as f64)?);
572 }
573 if let Some(array) = self.array
574 && args.len() < self.reads
575 {
576 args.push(array);
577 }
578 self.f.call_dynamic(caller, &args).await
579 }
580
581 pub(in crate::runtime::prelude) async fn test(
582 &self,
583 caller: &mut Caller<'_, StoreData>,
584 value: Val,
585 index: usize,
586 ) -> wasmtime::Result<bool> {
587 let result = self.call(caller, None, value, index).await?;
588 super::value::truthy(caller, &result)
589 }
590}
591
592pub async fn for_each(
594 caller: &mut Caller<'_, StoreData>,
595 array: Val,
596 elements: Vec<Val>,
597 f: &Closure,
598) -> wasmtime::Result<()> {
599 let f = ElementCallback::new(caller, f, Some(array))?;
600 for (index, elem) in elements.into_iter().enumerate() {
601 f.call(caller, None, elem, index).await?;
602 }
603 Ok(())
604}
605
606async fn map(
607 caller: &mut Caller<'_, StoreData>,
608 array: Val,
609 elements: Vec<Val>,
610 f: &Closure,
611) -> wasmtime::Result<Vec<Val>> {
612 let f = ElementCallback::new(caller, f, Some(array))?;
613 let mut out = KeptValues::with_capacity(caller, elements.len())?;
614 for (index, elem) in elements.into_iter().enumerate() {
615 let mapped = f.call(caller, None, elem, index).await?;
616 out.push(caller, mapped)?;
617 }
618 Ok(out.values().to_vec())
619}
620
621async fn filter(
622 caller: &mut Caller<'_, StoreData>,
623 array: Val,
624 elements: Vec<Val>,
625 pred: &Closure,
626) -> wasmtime::Result<Vec<Val>> {
627 let pred = ElementCallback::new(caller, pred, Some(array))?;
628 let mut out = Vec::new();
629 for (index, elem) in elements.into_iter().enumerate() {
630 if pred.test(caller, elem, index).await? {
631 out.push(elem);
632 }
633 }
634 Ok(out)
635}
636
637async fn reduce(
640 caller: &mut Caller<'_, StoreData>,
641 array: Val,
642 elements: Vec<Val>,
643 f: &Closure,
644 mut acc: Val,
645 reverse: bool,
646) -> wasmtime::Result<Val> {
647 let f = ElementCallback::new(caller, f, Some(array))?;
648 let mut indexed: Vec<(usize, Val)> = elements.into_iter().enumerate().collect();
649 if reverse {
650 indexed.reverse();
651 }
652 let kept_acc = KeptValue::new(caller)?;
654 for (index, elem) in indexed {
655 acc = f.call(caller, Some(acc), elem, index).await?;
656 kept_acc.set(caller, acc)?;
657 }
658 Ok(acc)
659}
660
661async fn find_match(
663 caller: &mut Caller<'_, StoreData>,
664 array: Val,
665 elements: &[Val],
666 pred: &Closure,
667 reverse: bool,
668) -> wasmtime::Result<Option<usize>> {
669 let pred = ElementCallback::new(caller, pred, Some(array))?;
670 let order: Vec<usize> = if reverse {
671 (0..elements.len()).rev().collect()
672 } else {
673 (0..elements.len()).collect()
674 };
675 for i in order {
676 if pred.test(caller, elements[i], i).await? {
677 return Ok(Some(i));
678 }
679 }
680 Ok(None)
681}
682
683async fn some(
684 caller: &mut Caller<'_, StoreData>,
685 array: Val,
686 elements: Vec<Val>,
687 pred: &Closure,
688) -> wasmtime::Result<bool> {
689 let pred = ElementCallback::new(caller, pred, Some(array))?;
690 for (index, elem) in elements.into_iter().enumerate() {
691 if pred.test(caller, elem, index).await? {
692 return Ok(true);
693 }
694 }
695 Ok(false)
696}
697
698async fn every(
699 caller: &mut Caller<'_, StoreData>,
700 array: Val,
701 elements: Vec<Val>,
702 pred: &Closure,
703) -> wasmtime::Result<bool> {
704 let pred = ElementCallback::new(caller, pred, Some(array))?;
705 for (index, elem) in elements.into_iter().enumerate() {
706 if !pred.test(caller, elem, index).await? {
707 return Ok(false);
708 }
709 }
710 Ok(true)
711}
712
713fn flat_into(
716 caller: &mut Caller<'_, StoreData>,
717 elements: Vec<Val>,
718 depth: i32,
719 out: &mut Vec<Val>,
720) -> wasmtime::Result<()> {
721 let mut frames = vec![(elements.into_iter(), depth)];
722 while let Some((elements, depth)) = frames.last_mut() {
723 let Some(elem) = elements.next() else {
724 frames.pop();
725 continue;
726 };
727 let depth = *depth;
728 if depth > 0 && is_array(caller, &elem)? {
729 if frames.len() >= crate::runtime::MAX_VTABLE_WALK_DEPTH as usize {
730 return Err(crate::runtime::host::range_error(format!(
731 "Array#flat exceeds {} levels of nesting; flatten fewer levels",
732 crate::runtime::MAX_VTABLE_WALK_DEPTH,
733 )));
734 }
735 let sub = read_array(caller, &elem, "Array#flat")?;
736 frames
737 .try_reserve(1)
738 .map_err(crate::runtime::host::fatal_host_error)?;
739 frames.push((sub.into_iter(), depth - 1));
740 } else {
741 out.try_reserve(1)
742 .map_err(crate::runtime::host::fatal_host_error)?;
743 out.push(elem);
744 }
745 }
746 Ok(())
747}
748
749async fn flat_map(
750 caller: &mut Caller<'_, StoreData>,
751 array: Val,
752 elements: Vec<Val>,
753 f: &Closure,
754) -> wasmtime::Result<Vec<Val>> {
755 let f = ElementCallback::new(caller, f, Some(array))?;
756 let kept_mapped = KeptValue::new(caller)?;
757 let mut out = KeptValues::with_capacity(caller, elements.len())?;
758 for (index, elem) in elements.into_iter().enumerate() {
759 let mapped = f.call(caller, None, elem, index).await?;
760 kept_mapped.set(caller, mapped)?;
763 let flattened = read_array(caller, &mapped, "Array#flatMap callback result")?;
764 out.extend(caller, &flattened)?;
765 }
766 Ok(out.values().to_vec())
767}
768
769fn array_step(
778 caller: &mut Caller<'_, StoreData>,
779 payload: &Val,
780 pos: i32,
781) -> wasmtime::Result<Option<(Val, Val)>> {
782 let storage = crate::runtime::array_storage::ArrayStorage::read(caller, payload)?;
783 let backing = storage.backing;
784 if pos < 0 || pos as u32 >= storage.len {
785 return Ok(None);
786 }
787 let elem = backing.get(&mut *caller, pos as u32)?;
788 let idx = box_number(caller, pos as f64)?;
789 Ok(Some((idx, elem)))
790}
791
792pub fn values(caller: &mut Caller<'_, StoreData>, array: &Val) -> wasmtime::Result<Val> {
793 make_index_iterator(caller, *array, IterKind::Values, array_step)
794}
795
796fn keys(caller: &mut Caller<'_, StoreData>, array: &Val) -> wasmtime::Result<Val> {
797 make_index_iterator(caller, *array, IterKind::Keys, array_step)
798}
799
800fn entries(caller: &mut Caller<'_, StoreData>, array: &Val) -> wasmtime::Result<Val> {
801 make_index_iterator(caller, *array, IterKind::Entries, array_step)
802}
803
804pub(super) async fn from(
816 caller: &mut Caller<'_, StoreData>,
817 src: &Val,
818 map_fn: &Val,
819) -> wasmtime::Result<Val> {
820 use crate::runtime::prelude::closure;
821 use crate::runtime::prelude::collection::{is_a, object_field, string_code_points, unbox_bool};
822
823 let map_closure = if super::undefined::is_undefined(caller, map_fn)? {
824 None
825 } else {
826 Some(closure::read_callback(caller, map_fn, "Array.from mapFn")?)
827 };
828 let map_fn = match &map_closure {
829 Some(c) => Some(ElementCallback::new(caller, c, None)?),
830 None => None,
831 };
832 let intr = intrinsic_types(&mut *caller)?;
833 let mut out = KeptValues::with_capacity(caller, 0)?;
834
835 if is_a(caller, src, &intr.array)? {
836 let mut pos: u32 = 0;
840 loop {
841 let storage = crate::runtime::array_storage::ArrayStorage::read(caller, src)?;
842 let backing = storage.backing;
843 if pos >= storage.len {
844 break;
845 }
846 out.reserve(caller, 1)?;
847 let elem = backing.get(&mut *caller, pos)?;
848 let mapped = apply_map(caller, &map_fn, elem, out.values().len()).await?;
849 out.push(caller, mapped)?;
850 pos += 1;
851 }
852 return build_array(caller, out.values());
853 }
854 if is_a(caller, src, &intr.string)? {
855 let cps = string_code_points(caller, src)?;
856 out.reserve(caller, cps.len())?;
857 for cp in cps {
858 let mapped = apply_map(caller, &map_fn, cp, out.values().len()).await?;
859 out.push(caller, mapped)?;
860 }
861 return build_array(caller, out.values());
862 }
863
864 let kept_iterator = KeptValue::new(caller)?;
866 let kept_result = KeptValue::new(caller)?;
867 let it = if is_a(
868 caller,
869 src,
870 &super::map::map_backing_struct(caller.engine(), &intr)?,
871 )? {
872 super::map::entries(caller, src)?
873 } else if is_a(
874 caller,
875 src,
876 &super::set::set_backing_struct(caller.engine(), &intr)?,
877 )? {
878 super::set::values(caller, src)?
879 } else if let Some(iter_method) = object_field(caller, src, "iterator")? {
880 let c = closure::read(caller, &iter_method, "Array.from iterable")?;
881 c.call_with_receiver(caller, *src, &[]).await?
882 } else if object_field(caller, src, "next")?.is_none()
883 && let Some(length) = object_field(caller, src, "length")?
884 {
885 let length = array_like_length(caller, &length)?;
886 for index in 0..length {
887 out.reserve(caller, 1)?;
888 let hole = super::undefined::value(caller)?;
889 let mapped = apply_map(caller, &map_fn, hole, index).await?;
890 out.push(caller, mapped)?;
891 }
892 return build_array(caller, out.values());
893 } else {
894 *src
895 };
896 kept_iterator.set(caller, it)?;
897
898 let next = object_field(caller, &it, "next")?
899 .ok_or_else(|| wasmtime::Error::msg("Array.from: source is not iterable"))?;
900 let next_closure = closure::read(caller, &next, "Array.from iterator")?;
901 loop {
902 out.reserve(caller, 1)?;
903 let result = next_closure.call_with_receiver(caller, it, &[]).await?;
904 kept_result.set(caller, result)?;
905 let done = object_field(caller, &result, "done")?
906 .ok_or_else(|| wasmtime::Error::msg("Array.from: iterator result missing `done`"))?;
907 if unbox_bool(caller, &done)? {
908 break;
909 }
910 let value = object_field(caller, &result, "value")?
911 .ok_or_else(|| wasmtime::Error::msg("Array.from: iterator result missing `value`"))?;
912 let mapped = apply_map(caller, &map_fn, value, out.values().len()).await?;
913 out.push(caller, mapped)?;
914 }
915 build_array(caller, out.values())
916}
917
918fn array_like_length(caller: &mut Caller<'_, StoreData>, length: &Val) -> wasmtime::Result<usize> {
922 let not_a_number = || wasmtime::Error::msg("Array.from: `length` is not a number");
923 let Val::AnyRef(Some(any)) = length else {
924 return Err(not_a_number());
925 };
926 let st = any.as_struct(&mut *caller)?.ok_or_else(not_a_number)?;
927 let Val::F64(bits) = st.field(&mut *caller, 1)? else {
928 return Err(not_a_number());
929 };
930 let length = f64::from_bits(bits);
931 if length.is_nan() || length <= 0.0 {
932 return Ok(0);
933 }
934 let length = length.trunc();
935 let invalid = || crate::runtime::host::range_error("Invalid array length");
936 if length > f64::from(u32::MAX) {
937 return Err(invalid());
938 }
939 usize::try_from(length as u32).map_err(|_| invalid())
940}
941
942async fn apply_map(
943 caller: &mut Caller<'_, StoreData>,
944 map_fn: &Option<ElementCallback<'_>>,
945 value: Val,
946 index: usize,
947) -> wasmtime::Result<Val> {
948 match map_fn {
949 Some(f) => f.call(caller, None, value, index).await,
950 None => Ok(value),
951 }
952}