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