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