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