Skip to main content

submilli_engine/runtime/prelude/uint8array/
install.rs

1//! ABI wiring for the Rust `Uint8Array` / `Uint8ArrayConstructor` methods:
2//! marshals `$Uint8Array`/`$Array`/`$Closure`/`$string`, registers each method
3//! under its dispatch key, and declares the value symbols codegen routes through.
4//! The byte operations themselves live in the parent module.
5
6use crate::runtime::host::{abi_arg, abi_result};
7use wasmtime::{FuncType, HeapType, Linker, RefType, StructType, Val, ValType};
8
9use crate::runtime::StoreData;
10use crate::runtime::fuel;
11use crate::runtime::host::{
12    intrinsic_array_type, intrinsic_string_type, intrinsic_uint8_array_type, register_host_fn,
13    register_host_fn_async, write_submilli_string_struct, write_submilli_string_struct_units,
14};
15use crate::runtime::intrinsic_types::{IntrinsicTypes, build_intrinsic_types, intrinsic_types};
16use crate::runtime::prelude::vtable::read_string_units;
17use crate::runtime::prelude::{MODULE_NAME, closure, declare_method};
18use crate::{MangledName, PackageDeclaration, Param, Type};
19
20/// Dispatch key for an instance method `Uint8Array#<m>`.
21/// `Uint8Array.BYTES_PER_ELEMENT`, and the instance property of that name.
22const BYTES_PER_ELEMENT: f64 = 1.0;
23
24/// `Uint8Array.BYTES_PER_ELEMENT` as a host-owned global, like the `Number`
25/// statics: a value symbol the guest imports.
26pub(crate) fn install_constants(
27    linker: &mut Linker<StoreData>,
28    store: &mut wasmtime::Store<StoreData>,
29) -> wasmtime::Result<()> {
30    let gty = wasmtime::GlobalType::new(ValType::F64, wasmtime::Mutability::Var);
31    let global = wasmtime::Global::new(&mut *store, gty, Val::F64(BYTES_PER_ELEMENT.to_bits()))?;
32    let mangled = ctor_key("BYTES_PER_ELEMENT");
33    linker.define(&mut *store, MODULE_NAME, mangled.as_str(), global)?;
34    Ok(())
35}
36
37fn method_key(method: &str) -> MangledName {
38    crate::mangle::extend(&crate::mangle::prelude("Uint8Array"), method)
39}
40
41/// Dispatch key for a `Uint8ArrayConstructor` static (`Uint8Array.fromHex`).
42fn ctor_key(method: &str) -> MangledName {
43    crate::mangle::extend(&crate::mangle::prelude("Uint8ArrayConstructor"), method)
44}
45
46fn ref_to(struct_ty: StructType) -> ValType {
47    ValType::Ref(RefType::new(false, HeapType::ConcreteStruct(struct_ty)))
48}
49
50/// A `(ref null $Object)` — the `at`/`find`/`reduce` boxed-number return, the
51/// `reduce` accumulator, and the nullable `sort` comparator / `Base64Options`.
52fn object_ref(intr: &IntrinsicTypes) -> ValType {
53    ValType::Ref(RefType::new(
54        true,
55        HeapType::ConcreteStruct(intr.object.clone()),
56    ))
57}
58
59fn f64v(v: &Val) -> f64 {
60    match v {
61        Val::F64(bits) => f64::from_bits(*bits),
62        _ => f64::NAN,
63    }
64}
65
66fn string_val(caller: &mut wasmtime::Caller<'_, StoreData>, s: &str) -> wasmtime::Result<Val> {
67    let st = write_submilli_string_struct(caller, s)?;
68    Ok(Val::AnyRef(Some(st.to_anyref())))
69}
70
71#[allow(clippy::too_many_lines)]
72pub fn install(linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
73    let engine = linker.engine().clone();
74    let intr = build_intrinsic_types(&engine)?;
75    let uint8 = ref_to(intrinsic_uint8_array_type(&engine)?);
76    let string = ref_to(intrinsic_string_type(&engine)?);
77    let array = ref_to(intrinsic_array_type(&engine)?);
78    let obj = object_ref(&intr);
79    let num = ValType::F64;
80    let boolean = ValType::I32;
81    // Callbacks cross erased, as `Array`'s do.
82    let callback = obj.clone();
83
84    let ft = |params: Vec<ValType>, results: Vec<ValType>| FuncType::new(&engine, params, results);
85
86    // --- Accessors / pure value methods ----------------------------------
87    register_host_fn(
88        linker,
89        MODULE_NAME,
90        method_key("length"),
91        ft(vec![uint8.clone()], vec![num.clone()]),
92        |caller, params, results| {
93            *abi_result(results, 0)? = Val::F64(
94                super::length(caller, abi_arg(params, 0)?, "Uint8Array#length")?.to_bits(),
95            );
96            Ok(())
97        },
98    )?;
99    register_host_fn(
100        linker,
101        MODULE_NAME,
102        method_key("BYTES_PER_ELEMENT"),
103        ft(vec![uint8.clone()], vec![num.clone()]),
104        |_caller, _params, results| {
105            *abi_result(results, 0)? = Val::F64(BYTES_PER_ELEMENT.to_bits());
106            Ok(())
107        },
108    )?;
109    register_host_fn(
110        linker,
111        MODULE_NAME,
112        method_key("byteLength"),
113        ft(vec![uint8.clone()], vec![num.clone()]),
114        |caller, params, results| {
115            *abi_result(results, 0)? = Val::F64(
116                super::length(caller, abi_arg(params, 0)?, "Uint8Array#byteLength")?.to_bits(),
117            );
118            Ok(())
119        },
120    )?;
121    register_host_fn(
122        linker,
123        MODULE_NAME,
124        method_key("at"),
125        ft(vec![uint8.clone(), num.clone()], vec![obj.clone()]),
126        |caller, params, results| {
127            *abi_result(results, 0)? = super::at(
128                caller,
129                abi_arg(params, 0)?,
130                f64v(abi_arg(params, 1)?),
131                "Uint8Array#at",
132            )?;
133            Ok(())
134        },
135    )?;
136    for (name, kind) in [
137        ("keys", super::IterKind::Keys),
138        ("values", super::IterKind::Values),
139        ("iterator", super::IterKind::Values),
140        ("entries", super::IterKind::Entries),
141    ] {
142        register_host_fn(
143            linker,
144            MODULE_NAME,
145            method_key(name),
146            ft(vec![uint8.clone()], vec![obj.clone()]),
147            move |caller, params, results| {
148                *abi_result(results, 0)? = super::iterate(caller, abi_arg(params, 0)?, kind)?;
149                Ok(())
150            },
151        )?;
152    }
153    for name in ["slice", "subarray"] {
154        register_host_fn(
155            linker,
156            MODULE_NAME,
157            method_key(name),
158            ft(
159                vec![uint8.clone(), num.clone(), num.clone()],
160                vec![uint8.clone()],
161            ),
162            |caller, params, results| {
163                let out = super::slice(
164                    caller,
165                    abi_arg(params, 0)?,
166                    f64v(abi_arg(params, 1)?),
167                    f64v(abi_arg(params, 2)?),
168                    "Uint8Array#slice",
169                )?;
170                *abi_result(results, 0)? = super::build(caller, &out)?;
171                Ok(())
172            },
173        )?;
174    }
175    register_host_fn(
176        linker,
177        MODULE_NAME,
178        method_key("with"),
179        ft(
180            vec![uint8.clone(), num.clone(), num.clone()],
181            vec![uint8.clone()],
182        ),
183        |caller, params, results| {
184            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#with")?;
185            let Some(out) =
186                super::with(&bytes, f64v(abi_arg(params, 1)?), f64v(abi_arg(params, 2)?))
187            else {
188                crate::runtime::fuel::charge(&mut *caller, crate::runtime::fuel::PARSE, 1)?;
189                return Err(crate::runtime::host::range_error(format!(
190                    "index {} is out of range (length {})",
191                    crate::runtime::number::format_number_js(f64v(abi_arg(params, 1)?)),
192                    bytes.len()
193                )));
194            };
195            *abi_result(results, 0)? = super::build(caller, &out)?;
196            Ok(())
197        },
198    )?;
199    for name in ["indexOf", "lastIndexOf"] {
200        let last = name == "lastIndexOf";
201        register_host_fn(
202            linker,
203            MODULE_NAME,
204            method_key(name),
205            ft(
206                vec![uint8.clone(), num.clone(), num.clone()],
207                vec![num.clone()],
208            ),
209            move |caller, params, results| {
210                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#indexOf")?;
211                let r = if last {
212                    super::last_index_of(
213                        &bytes,
214                        f64v(abi_arg(params, 1)?),
215                        f64v(abi_arg(params, 2)?),
216                    )
217                } else {
218                    super::index_of(&bytes, f64v(abi_arg(params, 1)?), f64v(abi_arg(params, 2)?))
219                };
220                *abi_result(results, 0)? = Val::F64(r.to_bits());
221                Ok(())
222            },
223        )?;
224    }
225    register_host_fn(
226        linker,
227        MODULE_NAME,
228        method_key("includes"),
229        ft(
230            vec![uint8.clone(), num.clone(), num.clone()],
231            vec![boolean.clone()],
232        ),
233        |caller, params, results| {
234            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#includes")?;
235            let r = super::includes(&bytes, f64v(abi_arg(params, 1)?), f64v(abi_arg(params, 2)?));
236            *abi_result(results, 0)? = Val::I32(i32::from(r));
237            Ok(())
238        },
239    )?;
240    register_host_fn(
241        linker,
242        MODULE_NAME,
243        method_key("join"),
244        ft(vec![uint8.clone(), string.clone()], vec![string.clone()]),
245        |caller, params, results| {
246            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#join")?;
247            let sep = read_string_units(caller, abi_arg(params, 1)?, "Uint8Array#join separator")?;
248            let out = super::join(&bytes, &sep);
249            *abi_result(results, 0)? = {
250                let st = write_submilli_string_struct_units(caller, &out)?;
251                Val::AnyRef(Some(st.to_anyref()))
252            };
253            Ok(())
254        },
255    )?;
256    register_host_fn(
257        linker,
258        MODULE_NAME,
259        method_key("toString"),
260        ft(vec![uint8.clone()], vec![string.clone()]),
261        |caller, params, results| {
262            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toString")?;
263            let out = super::join(&bytes, &[u16::from(b',')]);
264            *abi_result(results, 0)? = {
265                let st = write_submilli_string_struct_units(caller, &out)?;
266                Val::AnyRef(Some(st.to_anyref()))
267            };
268            Ok(())
269        },
270    )?;
271    register_host_fn(
272        linker,
273        MODULE_NAME,
274        method_key("toJson"),
275        ft(vec![uint8.clone()], vec![string.clone()]),
276        |caller, params, results| {
277            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toJson")?;
278            let json = format!("\"{}\"", super::to_base64_standard(&bytes));
279            *abi_result(results, 0)? = string_val(caller, &json)?;
280            Ok(())
281        },
282    )?;
283    register_host_fn(
284        linker,
285        MODULE_NAME,
286        method_key("toHex"),
287        ft(vec![uint8.clone()], vec![string.clone()]),
288        |caller, params, results| {
289            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toHex")?;
290            *abi_result(results, 0)? = string_val(caller, &super::to_hex(&bytes))?;
291            Ok(())
292        },
293    )?;
294    register_host_fn(
295        linker,
296        MODULE_NAME,
297        method_key("toBase64"),
298        ft(vec![uint8.clone(), obj.clone()], vec![string.clone()]),
299        |caller, params, results| {
300            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toBase64")?;
301            let (url_safe, omit) = super::read_base64_options(caller, abi_arg(params, 1)?)?;
302            fuel::charge(&mut *caller, fuel::SCAN, bytes.len() as u64)?;
303            *abi_result(results, 0)? =
304                string_val(caller, &super::encode_base64(&bytes, url_safe, omit))?;
305            Ok(())
306        },
307    )?;
308    register_host_fn(
309        linker,
310        MODULE_NAME,
311        method_key("equals"),
312        ft(vec![uint8.clone(), uint8.clone()], vec![boolean.clone()]),
313        |caller, params, results| {
314            let a = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#equals")?;
315            let b = super::read_bytes(caller, abi_arg(params, 1)?, "Uint8Array#equals")?;
316            *abi_result(results, 0)? = Val::I32(i32::from(super::equals(&a, &b)));
317            Ok(())
318        },
319    )?;
320
321    // --- In-place mutators ------------------------------------------------
322    register_host_fn(
323        linker,
324        MODULE_NAME,
325        method_key("reverse"),
326        ft(vec![uint8.clone()], vec![uint8.clone()]),
327        |caller, params, results| {
328            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#reverse")?;
329            *abi_result(results, 0)? = super::reverse(caller, abi_arg(params, 0)?, bytes)?;
330            Ok(())
331        },
332    )?;
333    register_host_fn(
334        linker,
335        MODULE_NAME,
336        method_key("fill"),
337        ft(
338            vec![uint8.clone(), num.clone(), num.clone(), num.clone()],
339            vec![uint8.clone()],
340        ),
341        |caller, params, results| {
342            *abi_result(results, 0)? = super::fill(
343                caller,
344                abi_arg(params, 0)?,
345                f64v(abi_arg(params, 1)?),
346                f64v(abi_arg(params, 2)?),
347                f64v(abi_arg(params, 3)?),
348            )?;
349            Ok(())
350        },
351    )?;
352    register_host_fn(
353        linker,
354        MODULE_NAME,
355        method_key("copyWithin"),
356        ft(
357            vec![uint8.clone(), num.clone(), num.clone(), num.clone()],
358            vec![uint8.clone()],
359        ),
360        |caller, params, results| {
361            *abi_result(results, 0)? = super::copy_within(
362                caller,
363                abi_arg(params, 0)?,
364                f64v(abi_arg(params, 1)?),
365                f64v(abi_arg(params, 2)?),
366                f64v(abi_arg(params, 3)?),
367            )?;
368            Ok(())
369        },
370    )?;
371    register_host_fn(
372        linker,
373        MODULE_NAME,
374        method_key("set"),
375        ft(vec![uint8.clone(), uint8.clone(), num.clone()], vec![]),
376        |caller, params, _results| {
377            super::set(
378                caller,
379                abi_arg(params, 0)?,
380                abi_arg(params, 1)?,
381                f64v(abi_arg(params, 2)?),
382            )
383        },
384    )?;
385    register_host_fn_async(
386        linker,
387        MODULE_NAME,
388        method_key("sort"),
389        ft(vec![uint8.clone(), obj.clone()], vec![uint8.clone()]),
390        |caller, params, results| {
391            Box::pin(async move {
392                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#sort")?;
393                let cmp =
394                    read_comparator(caller, abi_arg(params, 1)?, "Uint8Array#sort comparator")?;
395                *abi_result(results, 0)? =
396                    super::sort(caller, abi_arg(params, 0)?, bytes, cmp).await?;
397                Ok(())
398            })
399        },
400    )?;
401
402    // --- Immutable variants ----------------------------------------------
403    register_host_fn(
404        linker,
405        MODULE_NAME,
406        method_key("toReversed"),
407        ft(vec![uint8.clone()], vec![uint8.clone()]),
408        |caller, params, results| {
409            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toReversed")?;
410            let out = super::to_reversed(bytes);
411            *abi_result(results, 0)? = super::build(caller, &out)?;
412            Ok(())
413        },
414    )?;
415    register_host_fn_async(
416        linker,
417        MODULE_NAME,
418        method_key("toSorted"),
419        ft(vec![uint8.clone(), obj.clone()], vec![uint8.clone()]),
420        |caller, params, results| {
421            Box::pin(async move {
422                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#toSorted")?;
423                let cmp = read_comparator(
424                    caller,
425                    abi_arg(params, 1)?,
426                    "Uint8Array#toSorted comparator",
427                )?;
428                let out = super::to_sorted(caller, bytes, cmp).await?;
429                *abi_result(results, 0)? = super::build(caller, &out)?;
430                Ok(())
431            })
432        },
433    )?;
434
435    // --- Higher-order -----------------------------------------------------
436    register_host_fn_async(
437        linker,
438        MODULE_NAME,
439        method_key("forEach"),
440        ft(vec![uint8.clone(), callback.clone()], vec![]),
441        |caller, params, _results| {
442            Box::pin(async move {
443                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#forEach")?;
444                let f = closure::read_callback(
445                    caller,
446                    abi_arg(params, 1)?,
447                    "Uint8Array#forEach callback",
448                )?;
449                super::for_each(caller, *abi_arg(params, 0)?, bytes, &f).await
450            })
451        },
452    )?;
453    register_host_fn_async(
454        linker,
455        MODULE_NAME,
456        method_key("map"),
457        ft(vec![uint8.clone(), callback.clone()], vec![uint8.clone()]),
458        |caller, params, results| {
459            Box::pin(async move {
460                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#map")?;
461                let f =
462                    closure::read_callback(caller, abi_arg(params, 1)?, "Uint8Array#map callback")?;
463                let out = super::map(caller, *abi_arg(params, 0)?, bytes, &f).await?;
464                *abi_result(results, 0)? = super::build(caller, &out)?;
465                Ok(())
466            })
467        },
468    )?;
469    register_host_fn_async(
470        linker,
471        MODULE_NAME,
472        method_key("filter"),
473        ft(vec![uint8.clone(), callback.clone()], vec![uint8.clone()]),
474        |caller, params, results| {
475            Box::pin(async move {
476                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#filter")?;
477                let pred = closure::read_callback(
478                    caller,
479                    abi_arg(params, 1)?,
480                    "Uint8Array#filter predicate",
481                )?;
482                let out = super::filter(caller, *abi_arg(params, 0)?, bytes, &pred).await?;
483                *abi_result(results, 0)? = super::build(caller, &out)?;
484                Ok(())
485            })
486        },
487    )?;
488    for (name, reverse) in [("reduce", false), ("reduceRight", true)] {
489        register_host_fn_async(
490            linker,
491            MODULE_NAME,
492            method_key(name),
493            ft(
494                vec![uint8.clone(), callback.clone(), obj.clone()],
495                vec![obj.clone()],
496            ),
497            move |caller, params, results| {
498                Box::pin(async move {
499                    let bytes =
500                        super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#reduce")?;
501                    let f = closure::read_callback(
502                        caller,
503                        abi_arg(params, 1)?,
504                        "Uint8Array#reduce callback",
505                    )?;
506                    *abi_result(results, 0)? = super::reduce(
507                        caller,
508                        *abi_arg(params, 0)?,
509                        bytes,
510                        &f,
511                        *abi_arg(params, 2)?,
512                        reverse,
513                    )
514                    .await?;
515                    Ok(())
516                })
517            },
518        )?;
519    }
520    for (name, reverse) in [("find", false), ("findLast", true)] {
521        register_host_fn_async(
522            linker,
523            MODULE_NAME,
524            method_key(name),
525            ft(vec![uint8.clone(), callback.clone()], vec![obj.clone()]),
526            move |caller, params, results| {
527                Box::pin(async move {
528                    let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#find")?;
529                    let pred = closure::read_callback(
530                        caller,
531                        abi_arg(params, 1)?,
532                        "Uint8Array#find predicate",
533                    )?;
534                    *abi_result(results, 0)? = match super::find_match(
535                        caller,
536                        *abi_arg(params, 0)?,
537                        &bytes,
538                        &pred,
539                        reverse,
540                    )
541                    .await?
542                    {
543                        Some(i) => {
544                            let byte = *bytes.get(i).ok_or_else(|| {
545                                crate::runtime::host::fatal_host_error(
546                                    "Uint8Array#find: invalid result index",
547                                )
548                            })?;
549                            super::box_byte(caller, byte)?
550                        }
551                        None => crate::runtime::prelude::undefined::value(caller)?,
552                    };
553                    Ok(())
554                })
555            },
556        )?;
557    }
558    for (name, reverse) in [("findIndex", false), ("findLastIndex", true)] {
559        register_host_fn_async(
560            linker,
561            MODULE_NAME,
562            method_key(name),
563            ft(vec![uint8.clone(), callback.clone()], vec![num.clone()]),
564            move |caller, params, results| {
565                Box::pin(async move {
566                    let bytes =
567                        super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#findIndex")?;
568                    let pred = closure::read_callback(
569                        caller,
570                        abi_arg(params, 1)?,
571                        "Uint8Array#findIndex predicate",
572                    )?;
573                    let idx =
574                        super::find_match(caller, *abi_arg(params, 0)?, &bytes, &pred, reverse)
575                            .await?;
576                    let r = idx.map_or(-1.0, |i| i as f64);
577                    *abi_result(results, 0)? = Val::F64(r.to_bits());
578                    Ok(())
579                })
580            },
581        )?;
582    }
583    register_host_fn_async(
584        linker,
585        MODULE_NAME,
586        method_key("some"),
587        ft(vec![uint8.clone(), callback.clone()], vec![boolean.clone()]),
588        |caller, params, results| {
589            Box::pin(async move {
590                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#some")?;
591                let pred = closure::read_callback(
592                    caller,
593                    abi_arg(params, 1)?,
594                    "Uint8Array#some predicate",
595                )?;
596                let r = super::some(caller, *abi_arg(params, 0)?, bytes, &pred).await?;
597                *abi_result(results, 0)? = Val::I32(i32::from(r));
598                Ok(())
599            })
600        },
601    )?;
602    register_host_fn_async(
603        linker,
604        MODULE_NAME,
605        method_key("every"),
606        ft(vec![uint8.clone(), callback.clone()], vec![boolean.clone()]),
607        |caller, params, results| {
608            Box::pin(async move {
609                let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array#every")?;
610                let pred = closure::read_callback(
611                    caller,
612                    abi_arg(params, 1)?,
613                    "Uint8Array#every predicate",
614                )?;
615                let r = super::every(caller, *abi_arg(params, 0)?, bytes, &pred).await?;
616                *abi_result(results, 0)? = Val::I32(i32::from(r));
617                Ok(())
618            })
619        },
620    )?;
621
622    // --- Uint8ArrayConstructor statics -----------------------------------
623    for (name, label) in [
624        ("fromArray", "Uint8Array.fromArray"),
625        ("of", "Uint8Array.of"),
626    ] {
627        register_host_fn(
628            linker,
629            MODULE_NAME,
630            ctor_key(name),
631            ft(vec![array.clone()], vec![uint8.clone()]),
632            move |caller, params, results| {
633                let bytes = super::read_number_array(caller, abi_arg(params, 0)?, label)?;
634                *abi_result(results, 0)? = super::build(caller, &bytes)?;
635                Ok(())
636            },
637        )?;
638    }
639    // `new Uint8Array(x)` takes `number[] | number`, so its slot is the
640    // `$Object` union lowering — non-nullable, because the union has no `null`
641    // member. The arm is chosen at runtime: an `$Array` copies its elements, a
642    // boxed `number` is the JS length form.
643    let object_nonnull = ValType::Ref(RefType::new(
644        false,
645        HeapType::ConcreteStruct(intr.object.clone()),
646    ));
647    register_host_fn(
648        linker,
649        MODULE_NAME,
650        ctor_key("new"),
651        ft(vec![object_nonnull], vec![uint8.clone()]),
652        |caller, params, results| {
653            let intr = intrinsic_types(&mut *caller)?;
654            let bytes = if crate::runtime::prelude::collection::is_a(
655                caller,
656                abi_arg(params, 0)?,
657                &intr.array,
658            )? {
659                super::read_number_array(caller, abi_arg(params, 0)?, "Uint8Array.new")?
660            } else {
661                let n = crate::runtime::host::read_boxed_number(
662                    caller,
663                    abi_arg(params, 0)?,
664                    "Uint8Array.new",
665                )?;
666                *abi_result(results, 0)? = super::allocate(caller, super::alloc_len(n)?)?;
667                return Ok(());
668            };
669            *abi_result(results, 0)? = super::build(caller, &bytes)?;
670            Ok(())
671        },
672    )?;
673    register_host_fn(
674        linker,
675        MODULE_NAME,
676        ctor_key("alloc"),
677        ft(vec![num.clone()], vec![uint8.clone()]),
678        |caller, params, results| {
679            let n = super::alloc_len(f64v(abi_arg(params, 0)?))?;
680            *abi_result(results, 0)? = super::allocate(caller, n)?;
681            Ok(())
682        },
683    )?;
684    register_host_fn(
685        linker,
686        MODULE_NAME,
687        ctor_key("fromBytes"),
688        ft(vec![uint8.clone()], vec![uint8.clone()]),
689        |caller, params, results| {
690            let bytes = super::read_bytes(caller, abi_arg(params, 0)?, "Uint8Array.fromBytes")?;
691            *abi_result(results, 0)? = super::build(caller, &bytes)?;
692            Ok(())
693        },
694    )?;
695    register_host_fn(
696        linker,
697        MODULE_NAME,
698        ctor_key("fromBase64"),
699        ft(vec![string.clone(), obj.clone()], vec![uint8.clone()]),
700        |caller, params, results| {
701            let units = read_string_units(caller, abi_arg(params, 0)?, "Uint8Array.fromBase64")?;
702            let s = String::from_utf16_lossy(&units);
703            let (url_safe, _) = super::read_base64_options(caller, abi_arg(params, 1)?)?;
704            fuel::charge(&mut *caller, fuel::SCAN, s.len() as u64)?;
705            let bytes = super::decode_base64(&s, url_safe)?;
706            *abi_result(results, 0)? = super::build(caller, &bytes)?;
707            Ok(())
708        },
709    )?;
710    register_host_fn(
711        linker,
712        MODULE_NAME,
713        ctor_key("fromHex"),
714        ft(vec![string.clone()], vec![uint8.clone()]),
715        |caller, params, results| {
716            let units = read_string_units(caller, abi_arg(params, 0)?, "Uint8Array.fromHex")?;
717            let bytes = super::from_hex(&units)?;
718            *abi_result(results, 0)? = super::build(caller, &bytes)?;
719            Ok(())
720        },
721    )?;
722    Ok(())
723}
724
725/// Read an optional comparator: `undefined` → default numeric order.
726fn read_comparator(
727    caller: &mut wasmtime::Caller<'_, StoreData>,
728    val: &Val,
729    name: &str,
730) -> wasmtime::Result<Option<closure::Closure>> {
731    if crate::runtime::prelude::undefined::is_undefined(caller, val)? {
732        Ok(None)
733    } else {
734        Ok(Some(closure::read_callback(caller, val, name)?))
735    }
736}
737
738/// TypeScript's `(value: number, index: number, array: Uint8Array)` callback
739/// parameters, after `leading` (`reduce`'s accumulator). A callback may declare
740/// fewer.
741fn byte_callback_params(leading: Vec<Type>) -> Vec<Type> {
742    leading
743        .into_iter()
744        .chain([Type::Number, Type::Number, Type::Uint8Array])
745        .collect()
746}
747
748pub fn declare(defs: &mut PackageDeclaration) {
749    let u8a = || Param::new("a", Type::Uint8Array);
750    // The static constant imports as a global, like `Number.EPSILON`.
751    let bytes_per_element = ctor_key("BYTES_PER_ELEMENT");
752    defs.values.insert(
753        bytes_per_element.as_str().to_string(),
754        crate::ValueSymbol {
755            name: "BYTES_PER_ELEMENT".to_string(),
756            mangled_name: bytes_per_element,
757            declaration_span: crate::Span::at(crate::FileId::PRELUDE),
758            kind: crate::ValueKind::Const {
759                ty: Type::Number,
760                doc: None,
761            },
762        },
763    );
764    // A callback's slot is erased (see `install`); its type for checking calls
765    // is in `declare_types`.
766    let callback = || Param::new("f", Type::Unknown);
767    let n = |name: &str| Param::new(name, Type::Number);
768    let u8_ret = Type::Uint8Array;
769    let comparator = || {
770        Type::Union(vec![
771            Type::Function {
772                optional: 0,
773                params: vec![Type::Number, Type::Number],
774                ret: Box::new(Type::Number),
775                predicate: None,
776                has_rest: false,
777            },
778            Type::Undefined,
779        ])
780    };
781    let base64_options = || {
782        Type::Union(vec![
783            Type::prelude_interface("Base64Options".to_string(), Vec::new()),
784            Type::Undefined,
785        ])
786    };
787
788    let m = |defs: &mut PackageDeclaration, name: &str, params: Vec<Param>, ret: Type| {
789        declare_method(defs, name, method_key(name), params, ret);
790    };
791
792    m(defs, "length", vec![u8a()], Type::Number);
793    m(defs, "byteLength", vec![u8a()], Type::Number);
794    m(defs, "BYTES_PER_ELEMENT", vec![u8a()], Type::Number);
795    m(
796        defs,
797        "at",
798        vec![u8a(), n("index")],
799        Type::Union(vec![Type::Number, Type::Undefined]),
800    );
801    let iter = |ty: Type| Type::prelude_interface("Iterator".to_string(), vec![ty]);
802    m(defs, "keys", vec![u8a()], iter(Type::Number));
803    m(defs, "values", vec![u8a()], iter(Type::Number));
804    m(defs, "iterator", vec![u8a()], iter(Type::Number));
805    m(
806        defs,
807        "entries",
808        vec![u8a()],
809        iter(Type::Tuple(vec![Type::Number, Type::Number].into())),
810    );
811    for name in ["slice", "subarray"] {
812        m(
813            defs,
814            name,
815            vec![u8a(), n("start"), n("end")],
816            u8_ret.clone(),
817        );
818    }
819    m(
820        defs,
821        "with",
822        vec![u8a(), n("index"), n("value")],
823        u8_ret.clone(),
824    );
825    for name in ["indexOf", "lastIndexOf"] {
826        m(
827            defs,
828            name,
829            vec![u8a(), n("value"), n("fromIndex")],
830            Type::Number,
831        );
832    }
833    m(
834        defs,
835        "includes",
836        vec![u8a(), n("value"), n("fromIndex")],
837        Type::Boolean,
838    );
839    m(
840        defs,
841        "join",
842        vec![u8a(), Param::new("sep", Type::String)],
843        Type::String,
844    );
845    m(defs, "toString", vec![u8a()], Type::String);
846    m(defs, "toJson", vec![u8a()], Type::String);
847    m(defs, "toHex", vec![u8a()], Type::String);
848    m(
849        defs,
850        "toBase64",
851        vec![u8a(), Param::new("options", base64_options())],
852        Type::String,
853    );
854    m(
855        defs,
856        "equals",
857        vec![u8a(), Param::new("other", Type::Uint8Array)],
858        Type::Boolean,
859    );
860
861    m(defs, "reverse", vec![u8a()], u8_ret.clone());
862    m(
863        defs,
864        "fill",
865        vec![u8a(), n("value"), n("start"), n("end")],
866        u8_ret.clone(),
867    );
868    m(
869        defs,
870        "copyWithin",
871        vec![u8a(), n("target"), n("start"), n("end")],
872        u8_ret.clone(),
873    );
874    m(
875        defs,
876        "set",
877        vec![u8a(), Param::new("source", Type::Uint8Array), n("offset")],
878        Type::Void,
879    );
880    m(
881        defs,
882        "sort",
883        vec![u8a(), Param::new("compareFn", comparator())],
884        u8_ret.clone(),
885    );
886    m(defs, "toReversed", vec![u8a()], u8_ret.clone());
887    m(
888        defs,
889        "toSorted",
890        vec![u8a(), Param::new("compareFn", comparator())],
891        u8_ret.clone(),
892    );
893
894    m(defs, "forEach", vec![u8a(), callback()], Type::Void);
895    for name in ["map", "filter"] {
896        m(defs, name, vec![u8a(), callback()], u8_ret.clone());
897    }
898    let u = || Type::TypeVar("U".to_string());
899    for name in ["reduce", "reduceRight"] {
900        m(
901            defs,
902            name,
903            vec![u8a(), callback(), Param::new("initial", u())],
904            u(),
905        );
906    }
907    for name in ["find", "findLast"] {
908        m(
909            defs,
910            name,
911            vec![u8a(), callback()],
912            Type::Union(vec![Type::Number, Type::Undefined]),
913        );
914    }
915    for name in ["findIndex", "findLastIndex"] {
916        m(defs, name, vec![u8a(), callback()], Type::Number);
917    }
918    for name in ["some", "every"] {
919        m(defs, name, vec![u8a(), callback()], Type::Boolean);
920    }
921
922    let items = || Param::new("items", Type::Array(Box::new(Type::Number)));
923    for name in ["fromArray", "of"] {
924        declare_method(defs, name, ctor_key(name), vec![items()], u8_ret.clone());
925    }
926    // `new Uint8Array(x)` also accepts the JS length form; the two arms share
927    // one slot (the `number[] | number` union lowering) and the host picks.
928    declare_method(
929        defs,
930        "new",
931        ctor_key("new"),
932        vec![Param::with_default(
933            "values",
934            Type::Union(vec![Type::Array(Box::new(Type::Number)), Type::Number]),
935            crate::DefaultValue::Number(0.0),
936        )],
937        u8_ret.clone(),
938    );
939    declare_method(
940        defs,
941        "alloc",
942        ctor_key("alloc"),
943        vec![Param::new("length", Type::Number)],
944        u8_ret.clone(),
945    );
946    declare_method(
947        defs,
948        "fromBytes",
949        ctor_key("fromBytes"),
950        vec![Param::new("bytes", Type::Uint8Array)],
951        u8_ret.clone(),
952    );
953    declare_method(
954        defs,
955        "fromBase64",
956        ctor_key("fromBase64"),
957        vec![
958            Param::new("encoded", Type::String),
959            Param::new("options", base64_options()),
960        ],
961        u8_ret.clone(),
962    );
963    declare_method(
964        defs,
965        "fromHex",
966        ctor_key("fromHex"),
967        vec![Param::new("encoded", Type::String)],
968        u8_ret,
969    );
970}
971
972/// The type/interface surface this module implements — its slice of the
973/// prelude declaration (see `declaration::prelude_package_declaration`).
974#[allow(clippy::too_many_lines)]
975pub(crate) fn declare_types(defs: &mut crate::PackageDeclaration) {
976    use crate::runtime::prelude::declaration::doc;
977    use crate::{
978        Dispatch, MethodSig, Param, PropertySig, Span, Type, TypeKind, TypeSymbol, ValueKind,
979        ValueSymbol,
980    };
981    use std::collections::BTreeMap;
982    defs.types.insert(
983        "Uint8Array".to_string(),
984        TypeSymbol {
985            name: "Uint8Array".to_string(),
986            mangled_name: crate::mangle::prelude("Uint8Array"),
987            declaration_span: Span::at(crate::FileId::PRELUDE),
988            kind: TypeKind::Interface { index: None,
989                generics: Default::default(),
990                methods: BTreeMap::from([
991                    (
992                        "toString".to_string(),
993                        MethodSig {
994                            optional: false,
995                            generics: Default::default(),
996                            params: Vec::new(),
997                            ret: Type::String,
998                            predicate: None,
999                            doc: doc(
1000                                "/** Returns this array's bytes joined as a comma-separated decimal string — e.g. `Uint8Array.new([1, 2, 3]).toString() === \"1,2,3\"`. Matches the JS `Uint8Array.prototype.toString` shape. */",
1001                            ),
1002                        },
1003                    ),
1004                    (
1005                        "toJson".to_string(),
1006                        MethodSig {
1007                            optional: false,
1008                            generics: Default::default(),
1009                            params: Vec::new(),
1010                            ret: Type::String,
1011                            predicate: None,
1012                            doc: doc(
1013                                "/** Returns this array's bytes as a standard (padded) base64 string wrapped in `\"…\"` (the JSON string form). */",
1014                            ),
1015                        },
1016                    ),
1017                    (
1018                        "equals".to_string(),
1019                        MethodSig {
1020                            optional: false,
1021                            generics: Default::default(),
1022                            params: vec![Param::new("other", Type::Uint8Array)],
1023                            ret: Type::Boolean,
1024                            predicate: None,
1025                            doc: doc(
1026                                "/**\n * Byte-by-byte equality with `other`. Returns `false` when lengths differ.\n * @param other Bytes to compare against.\n */",
1027                            ),
1028                        },
1029                    ),
1030                    (
1031                        "join".to_string(),
1032                        MethodSig {
1033                            optional: false,
1034                            generics: Default::default(),
1035                            params: vec![Param::with_default(
1036                                "separator",
1037                                Type::String,
1038                                crate::DefaultValue::String(",".to_string()),
1039                            )],
1040                            ret: Type::String,
1041                            predicate: None,
1042                            doc: doc(
1043                                "/**\n * Returns this array's bytes formatted in decimal and concatenated with `separator` between adjacent pairs.\n * @param separator String placed between elements. Defaults to `\",\"`.\n */",
1044                            ),
1045                        },
1046                    ),
1047                    (
1048                        "reverse".to_string(),
1049                        MethodSig {
1050                            optional: false,
1051                            generics: Default::default(),
1052                            params: Vec::new(),
1053                            ret: Type::Uint8Array,
1054                            predicate: None,
1055                            doc: doc(
1056                                "/** Reverses this array's bytes in place and returns `this`. */",
1057                            ),
1058                        },
1059                    ),
1060                    (
1061                        "fill".to_string(),
1062                        MethodSig {
1063                            optional: false,
1064                            generics: Default::default(),
1065                            params: vec![
1066                                Param::new("value", Type::Number),
1067                                Param::with_default("start", Type::Number, crate::DefaultValue::Number(0.0)),
1068                                Param::with_default("end", Type::Number, crate::DefaultValue::Number(f64::INFINITY)),
1069                            ],
1070                            ret: Type::Uint8Array,
1071                            predicate: None,
1072                            doc: doc("/** Converts `value` to a byte and writes it to every position in `[start, end)`. Returns `this`. */"),
1073                        },
1074                    ),
1075                    (
1076                        "copyWithin".to_string(),
1077                        MethodSig {
1078                            optional: false,
1079                            generics: Default::default(),
1080                            params: vec![
1081                                Param::new("target", Type::Number),
1082                                Param::with_default("start", Type::Number, crate::DefaultValue::Number(0.0)),
1083                                Param::with_default("end", Type::Number, crate::DefaultValue::Number(f64::INFINITY)),
1084                            ],
1085                            ret: Type::Uint8Array,
1086                            predicate: None,
1087                            doc: doc("/** Copies `bytes[start..end)` to `bytes[target..]` in place. Returns `this`. */"),
1088                        },
1089                    ),
1090                    (
1091                        "slice".to_string(),
1092                        MethodSig {
1093                            optional: false,
1094                            generics: Default::default(),
1095                            params: vec![
1096                                Param::with_default("start", Type::Number, crate::DefaultValue::Number(0.0)),
1097                                Param::with_default("end", Type::Number, crate::DefaultValue::Number(f64::INFINITY)),
1098                            ],
1099                            ret: Type::Uint8Array,
1100                            predicate: None,
1101                            doc: doc("/** Returns a fresh copy of the bytes in `[start, end)`. */"),
1102                        },
1103                    ),
1104                    (
1105                        "subarray".to_string(),
1106                        MethodSig {
1107                            optional: false,
1108                            generics: Default::default(),
1109                            params: vec![
1110                                Param::with_default("start", Type::Number, crate::DefaultValue::Number(0.0)),
1111                                Param::with_default("end", Type::Number, crate::DefaultValue::Number(f64::INFINITY)),
1112                            ],
1113                            ret: Type::Uint8Array,
1114                            predicate: None,
1115                            doc: doc("/** Deep-copy alias for `slice` under v1 (no `ArrayBuffer` view sharing). */"),
1116                        },
1117                    ),
1118                    (
1119                        "with".to_string(),
1120                        MethodSig {
1121                            optional: false,
1122                            generics: Default::default(),
1123                            params: vec![
1124                                Param::new("index", Type::Number),
1125                                Param::new("value", Type::Number),
1126                            ],
1127                            ret: Type::Uint8Array,
1128                            predicate: None,
1129                            doc: doc("/** Returns a clone of this array with `value` converted to a byte and written at `index`. */"),
1130                        },
1131                    ),
1132                    (
1133                        "set".to_string(),
1134                        MethodSig {
1135                            optional: false,
1136                            generics: Default::default(),
1137                            params: vec![
1138                                Param::new("values", Type::Uint8Array),
1139                                Param::with_default("offset", Type::Number, crate::DefaultValue::Number(0.0)),
1140                            ],
1141                            ret: Type::Void,
1142                            predicate: None,
1143                            doc: doc("/** Copies `values` into this array starting at `offset`. Throws on out-of-bounds. */"),
1144                        },
1145                    ),
1146                    (
1147                        "forEach".to_string(),
1148                        MethodSig {
1149                            optional: false,
1150                            generics: Default::default(),
1151                            params: vec![Param::new("callback", Type::Function {
1152                                optional: 0,
1153                                params: byte_callback_params(Vec::new()),
1154                                ret: Box::new(Type::Void),
1155                                predicate: None,
1156                                has_rest: false,
1157                            })],
1158                            ret: Type::Void,
1159                            predicate: None,
1160                            doc: doc("/** Invokes `callback(byte, index, array)` for every byte in order. */"),
1161                        },
1162                    ),
1163                    (
1164                        "map".to_string(),
1165                        MethodSig {
1166                            optional: false,
1167                            generics: Default::default(),
1168                            params: vec![Param::new("callback", Type::Function {
1169                                optional: 0,
1170                                params: byte_callback_params(Vec::new()),
1171                                ret: Box::new(Type::Number),
1172                                predicate: None,
1173                                has_rest: false,
1174                            })],
1175                            ret: Type::Uint8Array,
1176                            predicate: None,
1177                            doc: doc("/** Returns a new `Uint8Array` with each `callback(this[i], i, this)` result converted to a byte. */"),
1178                        },
1179                    ),
1180                    (
1181                        "filter".to_string(),
1182                        MethodSig {
1183                            optional: false,
1184                            generics: Default::default(),
1185                            params: vec![Param::new("predicate", Type::Function {
1186                                optional: 0,
1187                                params: byte_callback_params(Vec::new()),
1188                                ret: Box::new(Type::Unknown),
1189                                predicate: None,
1190                                has_rest: false,
1191                            })],
1192                            ret: Type::Uint8Array,
1193                            predicate: None,
1194                            doc: doc("/** Returns a new `Uint8Array` containing every byte for which `predicate(byte, index, array)` returns a truthy value. */"),
1195                        },
1196                    ),
1197                    (
1198                        "some".to_string(),
1199                        MethodSig {
1200                            optional: false,
1201                            generics: Default::default(),
1202                            params: vec![Param::new("predicate", Type::Function {
1203                                optional: 0,
1204                                params: byte_callback_params(Vec::new()),
1205                                ret: Box::new(Type::Unknown),
1206                                predicate: None,
1207                                has_rest: false,
1208                            })],
1209                            ret: Type::Boolean,
1210                            predicate: None,
1211                            doc: doc("/** Returns `true` if `predicate` returns a truthy value for any byte. */"),
1212                        },
1213                    ),
1214                    (
1215                        "every".to_string(),
1216                        MethodSig {
1217                            optional: false,
1218                            generics: Default::default(),
1219                            params: vec![Param::new("predicate", Type::Function {
1220                                optional: 0,
1221                                params: byte_callback_params(Vec::new()),
1222                                ret: Box::new(Type::Unknown),
1223                                predicate: None,
1224                                has_rest: false,
1225                            })],
1226                            ret: Type::Boolean,
1227                            predicate: None,
1228                            doc: doc("/** Returns `true` iff `predicate(byte, index, array)` returns a truthy value for every byte. */"),
1229                        },
1230                    ),
1231                    (
1232                        "reduce".to_string(),
1233                        MethodSig {
1234                            optional: false,
1235                            generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1236                            params: vec![
1237                                Param::new("callback", Type::Function {
1238                                    optional: 0,
1239                                    params: byte_callback_params(vec![Type::TypeVar("U".to_string())]),
1240                                    ret: Box::new(Type::TypeVar("U".to_string())),
1241                                    predicate: None,
1242                                    has_rest: false,
1243                                }),
1244                                Param::new("initial", Type::TypeVar("U".to_string())),
1245                            ],
1246                            ret: Type::TypeVar("U".to_string()),
1247                            predicate: None,
1248                            doc: doc("/** Folds bytes left-to-right with `callback(acc, byte, index, array)`. */"),
1249                        },
1250                    ),
1251                    (
1252                        "reduceRight".to_string(),
1253                        MethodSig {
1254                            optional: false,
1255                            generics: crate::GenericParameters::unconstrained(vec!["U".to_string()]),
1256                            params: vec![
1257                                Param::new("callback", Type::Function {
1258                                    optional: 0,
1259                                    params: byte_callback_params(vec![Type::TypeVar("U".to_string())]),
1260                                    ret: Box::new(Type::TypeVar("U".to_string())),
1261                                    predicate: None,
1262                                    has_rest: false,
1263                                }),
1264                                Param::new("initial", Type::TypeVar("U".to_string())),
1265                            ],
1266                            ret: Type::TypeVar("U".to_string()),
1267                            predicate: None,
1268                            doc: doc("/** Folds bytes right-to-left with `callback(acc, byte, index, array)`. */"),
1269                        },
1270                    ),
1271                    (
1272                        "keys".to_string(),
1273                        MethodSig {
1274                            optional: false,
1275                            generics: Default::default(),
1276                            params: Vec::new(),
1277                            ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Number]),
1278                            predicate: None,
1279                            doc: doc("/** Returns a live `Iterator<number>` of the indices. */"),
1280                        },
1281                    ),
1282                    (
1283                        "values".to_string(),
1284                        MethodSig {
1285                            optional: false,
1286                            generics: Default::default(),
1287                            params: Vec::new(),
1288                            ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Number]),
1289                            predicate: None,
1290                            doc: doc("/** Returns a live `Iterator<number>` of the bytes; writes during iteration are seen. */"),
1291                        },
1292                    ),
1293                    (
1294                        "iterator".to_string(),
1295                        MethodSig {
1296                            optional: false,
1297                            generics: Default::default(),
1298                            params: Vec::new(),
1299                            ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Number]),
1300                            predicate: None,
1301                            doc: doc("/** Returns a live `Iterator<number>` of the bytes, which `for-of` and spread use. */"),
1302                        },
1303                    ),
1304                    (
1305                        "entries".to_string(),
1306                        MethodSig {
1307                            optional: false,
1308                            generics: Default::default(),
1309                            params: Vec::new(),
1310                            ret: Type::prelude_interface("Iterator".to_string(), vec![Type::Tuple(vec![Type::Number, Type::Number].into())]),
1311                            predicate: None,
1312                            doc: doc("/** Returns a live `Iterator<[number, number]>` of index/byte pairs. */"),
1313                        },
1314                    ),
1315                    (
1316                        "at".to_string(),
1317                        MethodSig {
1318                            optional: false,
1319                            generics: Default::default(),
1320                            params: vec![Param::new("index", Type::Number)],
1321                            ret: Type::Union(vec![Type::Number, Type::Undefined]),
1322                            predicate: None,
1323                            doc: doc("/** Returns the byte at `index`, or `undefined` if out of range. Negative indices count from the end. */"),
1324                        },
1325                    ),
1326                    (
1327                        "indexOf".to_string(),
1328                        MethodSig {
1329                            optional: false,
1330                            generics: Default::default(),
1331                            params: vec![
1332                                Param::new("target", Type::Number),
1333                                Param::with_default("fromIndex", Type::Number, crate::DefaultValue::Number(0.0)),
1334                            ],
1335                            ret: Type::Number,
1336                            predicate: None,
1337                            doc: doc("/** Returns the first index of `target`, or `-1`. */"),
1338                        },
1339                    ),
1340                    (
1341                        "lastIndexOf".to_string(),
1342                        MethodSig {
1343                            optional: false,
1344                            generics: Default::default(),
1345                            params: vec![
1346                                Param::new("target", Type::Number),
1347                                Param::with_default("fromIndex", Type::Number, crate::DefaultValue::OmittedNumber { omitted: f64::INFINITY, undefined: 0.0 }),
1348                            ],
1349                            ret: Type::Number,
1350                            predicate: None,
1351                            doc: doc("/** Returns the last index of `target`, or `-1`. */"),
1352                        },
1353                    ),
1354                    (
1355                        "includes".to_string(),
1356                        MethodSig {
1357                            optional: false,
1358                            generics: Default::default(),
1359                            params: vec![
1360                                Param::new("target", Type::Number),
1361                                Param::with_default("fromIndex", Type::Number, crate::DefaultValue::Number(0.0)),
1362                            ],
1363                            ret: Type::Boolean,
1364                            predicate: None,
1365                            doc: doc("/** Returns `true` if `target` appears at or after `fromIndex`. */"),
1366                        },
1367                    ),
1368                    (
1369                        "find".to_string(),
1370                        MethodSig {
1371                            optional: false,
1372                            generics: Default::default(),
1373                            params: vec![Param::new("predicate", Type::Function {
1374                                optional: 0,
1375                                params: byte_callback_params(Vec::new()),
1376                                ret: Box::new(Type::Boolean),
1377                                predicate: None,
1378                                has_rest: false,
1379                            })],
1380                            ret: Type::Union(vec![Type::Number, Type::Undefined]),
1381                            predicate: None,
1382                            doc: doc("/** Returns the first byte for which `predicate(byte, index, array)` returns `true`, or `undefined`. */"),
1383                        },
1384                    ),
1385                    (
1386                        "findLast".to_string(),
1387                        MethodSig {
1388                            optional: false,
1389                            generics: Default::default(),
1390                            params: vec![Param::new("predicate", Type::Function {
1391                                optional: 0,
1392                                params: byte_callback_params(Vec::new()),
1393                                ret: Box::new(Type::Unknown),
1394                                predicate: None,
1395                                has_rest: false,
1396                            })],
1397                            ret: Type::Union(vec![Type::Number, Type::Undefined]),
1398                            predicate: None,
1399                            doc: doc("/** Returns the last byte for which `predicate(byte, index, array)` returns a truthy value, or `undefined`. */"),
1400                        },
1401                    ),
1402                    (
1403                        "findIndex".to_string(),
1404                        MethodSig {
1405                            optional: false,
1406                            generics: Default::default(),
1407                            params: vec![Param::new("predicate", Type::Function {
1408                                optional: 0,
1409                                params: byte_callback_params(Vec::new()),
1410                                ret: Box::new(Type::Boolean),
1411                                predicate: None,
1412                                has_rest: false,
1413                            })],
1414                            ret: Type::Number,
1415                            predicate: None,
1416                            doc: doc("/** Returns the index of the first matching byte, or `-1`. */"),
1417                        },
1418                    ),
1419                    (
1420                        "findLastIndex".to_string(),
1421                        MethodSig {
1422                            optional: false,
1423                            generics: Default::default(),
1424                            params: vec![Param::new("predicate", Type::Function {
1425                                optional: 0,
1426                                params: byte_callback_params(Vec::new()),
1427                                ret: Box::new(Type::Unknown),
1428                                predicate: None,
1429                                has_rest: false,
1430                            })],
1431                            ret: Type::Number,
1432                            predicate: None,
1433                            doc: doc("/** Returns the index of the last matching byte, or `-1`. */"),
1434                        },
1435                    ),
1436                    (
1437                        "sort".to_string(),
1438                        MethodSig {
1439                            optional: false,
1440                            generics: Default::default(),
1441                            params: vec![Param::with_default(
1442                                "compareFn",
1443                                Type::Union(vec![
1444                                    Type::Function {
1445                                        optional: 0,
1446                                        params: vec![Type::Number, Type::Number],
1447                                        ret: Box::new(Type::Number),
1448                                        predicate: None,
1449                                        has_rest: false,
1450                                    },
1451                                    Type::Undefined,
1452                                ]),
1453                                crate::DefaultValue::Undefined,
1454                            )],
1455                            ret: Type::Uint8Array,
1456                            predicate: None,
1457                            doc: doc("/** Sorts bytes in place via `compareFn(a, b)`. With no `compareFn`, sorts numerically ascending. Returns `this`. */"),
1458                        },
1459                    ),
1460                    (
1461                        "toReversed".to_string(),
1462                        MethodSig {
1463                            optional: false,
1464                            generics: Default::default(),
1465                            params: Vec::new(),
1466                            ret: Type::Uint8Array,
1467                            predicate: None,
1468                            doc: doc("/** Returns a fresh copy with bytes reversed. */"),
1469                        },
1470                    ),
1471                    (
1472                        "toSorted".to_string(),
1473                        MethodSig {
1474                            optional: false,
1475                            generics: Default::default(),
1476                            params: vec![Param::with_default(
1477                                "compareFn",
1478                                Type::Union(vec![
1479                                    Type::Function {
1480                                        optional: 0,
1481                                        params: vec![Type::Number, Type::Number],
1482                                        ret: Box::new(Type::Number),
1483                                        predicate: None,
1484                                        has_rest: false,
1485                                    },
1486                                    Type::Undefined,
1487                                ]),
1488                                crate::DefaultValue::Undefined,
1489                            )],
1490                            ret: Type::Uint8Array,
1491                            predicate: None,
1492                            doc: doc("/** Returns a fresh copy sorted via `compareFn`. With no `compareFn`, sorts numerically ascending. */"),
1493                        },
1494                    ),
1495                    (
1496                        "toBase64".to_string(),
1497                        MethodSig {
1498                            optional: false,
1499                            generics: Default::default(),
1500                            params: vec![Param::with_default(
1501                                "options",
1502                                Type::Union(vec![
1503                                    Type::prelude_interface("Base64Options".to_string(), Vec::new()),
1504                                    Type::Undefined,
1505                                ]),
1506                                crate::DefaultValue::Undefined,
1507                            )],
1508                            ret: Type::String,
1509                            predicate: None,
1510                            doc: doc("/** Returns the bytes as a base64 string. `options` selects alphabet and padding. */"),
1511                        },
1512                    ),
1513                    (
1514                        "toHex".to_string(),
1515                        MethodSig {
1516                            optional: false,
1517                            generics: Default::default(),
1518                            params: Vec::new(),
1519                            ret: Type::String,
1520                            predicate: None,
1521                            doc: doc("/** Returns the bytes as a lowercase hex string. */"),
1522                        },
1523                    ),
1524                ]),
1525                properties: BTreeMap::from([
1526                    (
1527                        "length".to_string(),
1528                        PropertySig {
1529                            ty: Type::Number,
1530                            readonly: true,
1531                            intrinsic: false,
1532                            optional: false,
1533                            doc: doc("/** The number of bytes in this array. */"),
1534                        },
1535                    ),
1536                    (
1537                        "BYTES_PER_ELEMENT".to_string(),
1538                        PropertySig {
1539                            ty: Type::Number,
1540                            readonly: true,
1541                            intrinsic: false,
1542                            optional: false,
1543                            doc: doc("/** The size in bytes of each element: always `1`. */"),
1544                        },
1545                    ),
1546                    (
1547                        "byteLength".to_string(),
1548                        PropertySig {
1549                            ty: Type::Number,
1550                            readonly: true,
1551                            intrinsic: false,
1552                            optional: false,
1553                            doc: doc("/** Equivalent to `length`. Provided for JS `TypedArray` API compatibility. */"),
1554                        },
1555                    ),
1556                ]),
1557                dispatch: Dispatch::Direct,
1558                doc: doc(
1559                    "/** Packed byte array. Constructed via `new Uint8Array([...])` / `Uint8Array.alloc(n)` / `Uint8Array.fromArray(...)` / etc. */",
1560                ),
1561            },
1562        },
1563    );
1564
1565    defs.types.insert(
1566        "Uint8ArrayConstructor".to_string(),
1567        TypeSymbol {
1568            name: "Uint8ArrayConstructor".to_string(),
1569            mangled_name: crate::mangle::prelude("Uint8ArrayConstructor"),
1570            declaration_span: Span::at(crate::FileId::PRELUDE),
1571            kind: TypeKind::Interface { index: None,
1572                generics: Default::default(),
1573                methods: BTreeMap::from([
1574                    (
1575                        "new".to_string(),
1576                        MethodSig {
1577                            optional: false,
1578                            generics: Default::default(),
1579                            params: vec![Param::with_default(
1580                                "values",
1581                                Type::Union(vec![
1582                                    Type::Array(Box::new(Type::Number)),
1583                                    Type::Number,
1584                                ]),
1585                                crate::DefaultValue::Number(0.0),
1586                            )],
1587                            ret: Type::Uint8Array,
1588                            predicate: None,
1589                            doc: doc(
1590                                "/**\n * Build a new `Uint8Array`. Given an array, truncates each element and reduces it modulo 256, as JavaScript does, so `-1` is 255. Given a number, allocates that many zero bytes (the same as `Uint8Array.alloc`, including its `RangeError` on a negative or too-large length). With no argument, the array is empty.\n * @param values Numeric values to copy into the new array, or the length to allocate. Defaults to `0`.\n */",
1591                            ),
1592                        },
1593                    ),
1594                    (
1595                        "alloc".to_string(),
1596                        MethodSig {
1597                            optional: false,
1598                            generics: Default::default(),
1599                            params: vec![Param::new("n", Type::Number)],
1600                            ret: Type::Uint8Array,
1601                            predicate: None,
1602                            doc: doc(
1603                                "/**\n * Allocate a zero-filled `Uint8Array` of length `n`. Fractional values truncate toward zero and `NaN` gives an empty array; a negative or too-large `n` raises a `RangeError`.\n * @param n Length in bytes.\n */",
1604                            ),
1605                        },
1606                    ),
1607                    (
1608                        "fromArray".to_string(),
1609                        MethodSig {
1610                            optional: false,
1611                            generics: Default::default(),
1612                            params: vec![Param::new(
1613                                "values",
1614                                Type::Array(Box::new(Type::Number)),
1615                            )],
1616                            ret: Type::Uint8Array,
1617                            predicate: None,
1618                            doc: doc(
1619                                "/** Build a new `Uint8Array` from `values` — canonical name for `Uint8Array.new(values)`. */",
1620                            ),
1621                        },
1622                    ),
1623                    (
1624                        "fromBytes".to_string(),
1625                        MethodSig {
1626                            optional: false,
1627                            generics: Default::default(),
1628                            params: vec![Param::new("other", Type::Uint8Array)],
1629                            ret: Type::Uint8Array,
1630                            predicate: None,
1631                            doc: doc(
1632                                "/** Returns a deep copy of `other`. Mutations on the result don't touch `other`. */",
1633                            ),
1634                        },
1635                    ),
1636                    (
1637                        "of".to_string(),
1638                        MethodSig {
1639                            optional: false,
1640                            generics: Default::default(),
1641                            params: vec![Param::rest(
1642                                "values",
1643                                Type::Array(Box::new(Type::Number)),
1644                            )],
1645                            ret: Type::Uint8Array,
1646                            predicate: None,
1647                            doc: doc(
1648                                "/** Build a `Uint8Array` from the supplied byte values — `Uint8Array.of(1, 2, 3)`. */",
1649                            ),
1650                        },
1651                    ),
1652                    (
1653                        "fromBase64".to_string(),
1654                        MethodSig {
1655                            optional: false,
1656                            generics: Default::default(),
1657                            params: vec![
1658                                Param::new("s", Type::String),
1659                                Param::with_default(
1660                                    "options",
1661                                    Type::Union(vec![
1662                                        Type::prelude_interface("Base64Options".to_string(), Vec::new()),
1663                                        Type::Undefined,
1664                                    ]),
1665                                    crate::DefaultValue::Undefined,
1666                                ),
1667                            ],
1668                            ret: Type::Uint8Array,
1669                            predicate: None,
1670                            doc: doc(
1671                                "/** Decode `s` as base64; `options.alphabet` picks standard vs URL-safe. Malformed input throws a `SyntaxError`. */",
1672                            ),
1673                        },
1674                    ),
1675                    (
1676                        "fromHex".to_string(),
1677                        MethodSig {
1678                            optional: false,
1679                            generics: Default::default(),
1680                            params: vec![Param::new("s", Type::String)],
1681                            ret: Type::Uint8Array,
1682                            predicate: None,
1683                            doc: doc(
1684                                "/** Decode `s` as a hex string. Mixed case accepted; whitespace or an odd length throws a `SyntaxError`. */",
1685                            ),
1686                        },
1687                    ),
1688                ]),
1689                properties: BTreeMap::from([(
1690                    "BYTES_PER_ELEMENT".to_string(),
1691                    PropertySig {
1692                        ty: Type::Number,
1693                        readonly: true,
1694                        intrinsic: false,
1695                        optional: false,
1696                        doc: doc("/** The size in bytes of each element: always `1`. */"),
1697                    },
1698                )]),
1699                dispatch: Dispatch::Static,
1700                doc: doc(
1701                    "/** Constructor object for `Uint8Array`. Accessed via the global `Uint8Array` binding. */",
1702                ),
1703            },
1704        },
1705    );
1706
1707    defs.types.insert(
1708        "Base64Options".to_string(),
1709        TypeSymbol {
1710            name: "Base64Options".to_string(),
1711            mangled_name: crate::mangle::prelude("Base64Options"),
1712            declaration_span: Span::at(crate::FileId::PRELUDE),
1713            kind: TypeKind::Interface { index: None,
1714                generics: Default::default(),
1715                methods: BTreeMap::new(),
1716                properties: BTreeMap::from([
1717                    (
1718                        "alphabet".to_string(),
1719                        PropertySig {
1720                            ty: Type::Union(vec![
1721                                Type::StringLiteral("base64".to_string()),
1722                                Type::StringLiteral("base64url".to_string()),
1723                            ]),
1724                            readonly: false,
1725                            intrinsic: false,
1726                            optional: true,
1727                            doc: doc(
1728                                "/** Alphabet selector. `\"base64\"` (default) or `\"base64url\"`. */",
1729                            ),
1730                        },
1731                    ),
1732                    (
1733                        "omitPadding".to_string(),
1734                        PropertySig {
1735                            ty: Type::Boolean,
1736                            readonly: false,
1737                            intrinsic: false,
1738                            optional: true,
1739                            doc: doc(
1740                                "/** When `true`, omit the trailing `=` padding. Encode-only. */",
1741                            ),
1742                        },
1743                    ),
1744                ]),
1745                dispatch: Dispatch::VTable,
1746                doc: doc(
1747                    "/** Options bag for `Uint8Array#toBase64` / `Uint8Array.fromBase64`. All fields optional. */",
1748                ),
1749            },
1750        },
1751    );
1752
1753    defs.values.insert(
1754        "Uint8Array".to_string(),
1755        ValueSymbol {
1756            name: "Uint8Array".to_string(),
1757            mangled_name: crate::mangle::prelude("Uint8Array"),
1758            declaration_span: Span::at(crate::FileId::PRELUDE),
1759            kind: ValueKind::Const {
1760                ty: Type::prelude_interface("Uint8ArrayConstructor".to_string(), Vec::new()),
1761                doc: doc(
1762                    "/** The `Uint8Array` constructor — call `Uint8Array.new([...])` or `Uint8Array.alloc(n)` to make instances. */",
1763                ),
1764            },
1765        },
1766    );
1767}