1use async_lock::OnceCell as AsyncOnceCell;
2use js_sys::{Object, Reflect, Uint8Array};
3use std::cell::OnceCell;
4
5#[repr(transparent)]
6#[derive(Debug, Copy, Clone)]
7pub struct Bool32(pub u32);
8
9impl Bool32 {
10 pub fn is_ok(&self) -> bool {
11 self.0 != 0
12 }
13 pub fn is_err(&self) -> bool {
14 !self.is_ok()
15 }
16}
17
18mod binding {
19 use js_sys::Uint8Array;
20 use wasm_bindgen::prelude::*;
21
22 #[cfg(feature = "encoder")]
23 include!(concat!(env!("OUT_DIR"), "/wasm_encoder_binding.rs"));
24 #[cfg(not(feature = "encoder"))]
25 include!(concat!(env!("OUT_DIR"), "/wasm_transcoder_binding.rs"));
26}
27use binding::Basisu;
28
29#[cfg(feature = "encoder")]
30const BASISU_WASM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/build/basisu_encoder.wasm"));
31#[cfg(not(feature = "encoder"))]
32const BASISU_WASM: &[u8] =
33 include_bytes!(concat!(env!("OUT_DIR"), "/build/basisu_transcoder.wasm"));
34
35thread_local! {
36 static BASISU_INSTANCE: OnceCell<Basisu> = const { OnceCell::new() };
37}
38
39static BASISU_INITIALIZED: AsyncOnceCell<()> = AsyncOnceCell::new();
40
41mod instance {
42 use js_sys::Object;
43 use wasm_bindgen::prelude::wasm_bindgen;
44
45 use crate::web::binding::Basisu;
46
47 #[cfg(feature = "encoder")]
48 include!(concat!(env!("OUT_DIR"), "/wasm_encoder_inline_js.rs"));
49
50 #[cfg(not(feature = "encoder"))]
51 include!(concat!(env!("OUT_DIR"), "/wasm_transcoder_inline_js.rs"));
52}
53
54#[cfg_attr(docsrs, doc(cfg(all(
55 target_arch = "wasm32",
56 target_vendor = "unknown",
57 target_os = "unknown",
58))))]
59pub async fn instantiate_basisu_wasm() {
63 instantiate_custom_basisu_wasm(BASISU_WASM).await;
64}
65
66#[cfg_attr(docsrs, doc(cfg(all(
67 target_arch = "wasm32",
68 target_vendor = "unknown",
69 target_os = "unknown",
70))))]
71pub async fn instantiate_custom_basisu_wasm(wasm_data: &[u8]) {
75 BASISU_INITIALIZED
76 .get_or_init(async || {
77 let binary = Uint8Array::new_from_slice(wasm_data);
78 let args = Object::new();
79 Reflect::set(&args, &"wasmBinary".into(), &binary).unwrap();
80 let instance = instance::new_instance(&args).await;
81 BASISU_INSTANCE.with(|cell| {
82 cell.set(instance).unwrap();
83 });
84 })
85 .await;
86}
87
88#[cfg(feature = "encoder")]
89#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
90#[expect(
91 clippy::missing_safety_doc,
92 reason = "Generated basisu C API binding doesn't have safety doc"
93)]
94pub mod encoder {
95 use super::BASISU_INSTANCE;
96 use super::Bool32;
97 include!(concat!(env!("OUT_DIR"), "/wasm_encoder_pub_funcs.rs"));
98}
99
100#[expect(
101 clippy::missing_safety_doc,
102 clippy::too_many_arguments,
103 reason = "The binding is generated"
104)]
105pub mod transcoder {
106 use super::BASISU_INSTANCE;
107 use super::Bool32;
108 include!(concat!(env!("OUT_DIR"), "/wasm_transcoder_pub_funcs.rs"));
109}
110
111pub(crate) unsafe fn copy_host_memory_to_basisu_impl(data: &[u8], basisu_ptr: u64) {
112 BASISU_INSTANCE.with(|inst| {
113 let inst = inst.get().unwrap();
114 inst.wasm_heap_memory()
115 .set(&Uint8Array::from(data), basisu_ptr as u32);
116 });
117}
118
119pub(crate) unsafe fn copy_basisu_memory_to_host_impl(
120 basisu_ptr: u64,
121 count: u64,
122) -> alloc::vec::Vec<u8> {
123 BASISU_INSTANCE.with(|inst| {
124 let inst = inst.get().unwrap();
125 inst.wasm_heap_memory()
126 .subarray(basisu_ptr as u32, (basisu_ptr + count) as u32)
127 .to_vec()
128 })
129}