Skip to main content

basisu_c_sys/
web.rs

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))))]
59/// Instantiate the basisu wasm, required on web before calling other functions.
60///
61/// Once [`instantiate_basisu_wasm`]/[`instantiate_custom_basisu_wasm`] is called, the wasm can't be changed.
62pub 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))))]
71/// Instantiate the you custom basisu wasm, required on web before calling other functions. The wasm must be compatible with basisu C API.
72///
73/// Once [`instantiate_basisu_wasm`]/[`instantiate_custom_basisu_wasm`] is called, the wasm can't be changed.
74pub 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}