diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2122e5b99..18052710b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -94,7 +94,7 @@ jobs: - name: wasm-bindgen uses: jetli/wasm-bindgen-action@v0.1.0 with: - version: "0.2.108" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml + version: "0.2.126" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml - run: ./scripts/wasm_bindgen_check.sh --skip-setup diff --git a/Cargo.lock b/Cargo.lock index a377329a7..2ba363c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -548,9 +548,9 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" +checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d" dependencies = [ "bit-vec 0.9.1", ] @@ -1775,12 +1775,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -2006,7 +2000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e" dependencies = [ "bytemuck", - "foldhash 0.2.0", + "foldhash", "hashbrown 0.17.1", "log", "peniko", @@ -2107,26 +2101,6 @@ dependencies = [ "windows", ] -[[package]] -name = "gpu-descriptor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" -dependencies = [ - "bitflags 2.13.0", - "gpu-descriptor-types", - "hashbrown 0.15.5", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" -dependencies = [ - "bitflags 2.13.0", -] - [[package]] name = "guillotiere" version = "0.7.0" @@ -2160,15 +2134,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -2177,7 +2142,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -2186,7 +2151,7 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -2239,12 +2204,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hexf-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" - [[package]] name = "home" version = "0.5.12" @@ -2589,11 +2548,12 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -2849,22 +2809,22 @@ dependencies = [ [[package]] name = "naga" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bf919621e7975acb27d881bae2fb993e0d45c8e0446e85e6272971e00dc8df" +checksum = "23bf0a141a9ab6f07dbb492db53245e464bc9db42f407772d9ae03d83a2c1033" dependencies = [ "arrayvec", - "bit-set 0.9.1", + "bit-set 0.10.0", "bitflags 2.13.0", "cfg-if", "cfg_aliases", "codespan-reporting", "half", - "hashbrown 0.16.1", - "hexf-parse", + "hashbrown 0.17.1", "indexmap", "libm", "log", + "naga-types", "num-traits", "once_cell", "rustc-hash 1.1.0", @@ -2873,6 +2833,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "naga-types" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658200ddc25c6c7b860747516d132d1b284c0fafb7a380233acee9a72fb30e11" +dependencies = [ + "hashbrown 0.17.1", + "indexmap", + "rustc-hash 1.1.0", + "thiserror 2.0.18", +] + [[package]] name = "ndk" version = "0.9.0" @@ -3186,6 +3158,7 @@ dependencies = [ "bitflags 2.13.0", "objc2 0.6.4", "objc2-core-foundation", + "objc2-core-graphics", "objc2-foundation 0.3.2", "objc2-metal 0.3.2", ] @@ -4575,7 +4548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", @@ -5161,9 +5134,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -5174,23 +5147,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5198,9 +5167,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -5211,9 +5180,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -5329,9 +5298,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -5380,9 +5349,9 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e8840e1ba2881d4cbb18d2147627a56af426ff064c0401eb0c8410c6325d07" +checksum = "6d8f4bd44d92da5270f03409dba9f952dab24f128e05d6a554926101d1bf9114" dependencies = [ "arrayvec", "bitflags 2.13.0", @@ -5390,7 +5359,7 @@ dependencies = [ "cfg-if", "cfg_aliases", "document-features", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "js-sys", "log", "naga", @@ -5410,21 +5379,22 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f519832254e56965a9940c4af57dcb75f702b6f6fa4a0b172f685395843a4d7" +checksum = "08763620e76fc980bca7bf84de82568614487a53172dd968d89187282eb87fa2" dependencies = [ "arrayvec", - "bit-set 0.9.1", + "bit-set 0.10.0", "bit-vec 0.9.1", "bitflags 2.13.0", "bytemuck", "cfg_aliases", "document-features", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "indexmap", "log", "naga", + "naga-types", "once_cell", "parking_lot", "portable-atomic", @@ -5444,50 +5414,50 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e39e26c4c0e07589e67d18546cf79ff45383659fc72fca4dd293358a0347f3" +checksum = "3283b6da70d7fc892de95840215aa36381b5d0cbc479e88ee2b173c7b992b225" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e09be551dc939498bdd5f6b2c66e55ab275dad25825267a08605a80fc9f0af" +checksum = "85dcf2b2e5c2afb9eda64c570a87a4e570304bf39e52eddbaaf222d655b656ad" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1fb1798be2a912497d4c224f72d39bb0cb34af50e8bcc29865bc339c943059" +checksum = "2b6c13228950f36a56023976a6c4ee6714b27fb40e3d52a33f7d3bb6d109c0b1" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e592c1bbef6ad047647ae6e666ebd8cee7a32bb4544d9700ec96cbf73230257" +checksum = "f76bc9c1c186ff3d9054e0d224c93c8c1c79d6653907c5249a5c1ea1a2cb1e43" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ace1c17727311c22a46e4e3faf56ea6de81af99dcc839bdfb54857b94d448d" +checksum = "cf765132d8d5f50e192e7880464890c13f4e7457aafe8e5466e8174586e9f101" dependencies = [ "android_system_properties", "arrayvec", "ash", - "bit-set 0.9.1", + "bit-set 0.10.0", "bitflags 2.13.0", "block2 0.6.2", "bytemuck", @@ -5496,17 +5466,18 @@ dependencies = [ "glow", "glutin_wgl_sys", "gpu-allocator", - "gpu-descriptor", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "js-sys", "khronos-egl", "libc", "libloading", "log", "naga", + "naga-types", "ndk-sys", "objc2 0.6.4", "objc2-core-foundation", + "objc2-core-graphics", "objc2-foundation 0.3.2", "objc2-metal 0.3.2", "objc2-quartz-core 0.3.2", @@ -5521,6 +5492,7 @@ dependencies = [ "raw-window-metal", "renderdoc-sys", "smallvec", + "static_assertions", "thiserror 2.0.18", "wasm-bindgen", "wayland-sys", @@ -5534,9 +5506,9 @@ dependencies = [ [[package]] name = "wgpu-naga-bridge" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95226013f547544b223281cd16a4fb549aa9dcb562adbda0faae4c73ffbbc161" +checksum = "c9eaac644e5008925c78567d272b9d66ef83da55a53cc17fc7daade7bb6e66e5" dependencies = [ "naga", "wgpu-types", @@ -5544,15 +5516,17 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "29.0.4" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84bf84cd9ca8ca45e2b223a3868f1adf9bfc0c66aeac212e76ee7e40fdadf8f5" +checksum = "1a9c93c2b35edde326df60ffdee4c0f5864eac3011d6768b70d43f028ad93565" dependencies = [ "bitflags 2.13.0", "bytemuck", "js-sys", "log", + "naga-types", "raw-window-handle", + "static_assertions", "web-sys", ] diff --git a/Cargo.toml b/Cargo.toml index ff8c02003..78606c8d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,7 @@ home = "0.5.12" image = { version = "0.25.6", default-features = false } # Can't update to 0.25.7+: it needs png 0.18, which only matches resvg once resvg moves to tiny-skia 0.12 — blocked, see resvg below itertools = "0.15.0" jiff = { version = "0.2.29", default-features = false } -js-sys = "0.3.77" +js-sys = "0.3.103" kittest = { version = "0.4.0" } log = { version = "0.4.33", features = ["std"] } memoffset = "0.9.1" @@ -154,13 +154,13 @@ vello_cpu = { version = "0.0.9", default-features = false, features = [ "u8_pipeline", "f32_pipeline", ] } -wasm-bindgen = "0.2.108" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml. Don't update this spuriously, because of https://github.com/rerun-io/rerun/issues/8766 -wasm-bindgen-futures = "0.4.58" +wasm-bindgen = "0.2.126" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml. Don't update this spuriously, because of https://github.com/rerun-io/rerun/issues/8766 +wasm-bindgen-futures = "0.4.76" wayland-cursor = { version = "0.31.14", default-features = false } -web-sys = "0.3.77" +web-sys = "0.3.103" web-time = "1.1" # Timekeeping for native and web webbrowser = "1.2" -wgpu = { version = "29.0", default-features = false, features = ["std"] } +wgpu = { version = "30.0", default-features = false, features = ["std"] } windows-sys = "0.61.2" winit = { version = "0.30.13", default-features = false } diff --git a/crates/eframe/src/web/web_painter_wgpu.rs b/crates/eframe/src/web/web_painter_wgpu.rs index b16f98a9b..1728d7adc 100644 --- a/crates/eframe/src/web/web_painter_wgpu.rs +++ b/crates/eframe/src/web/web_painter_wgpu.rs @@ -380,7 +380,7 @@ impl WebPainter for WebPainterWgpu { ); } - frame.present(); + render_state.queue.present(frame); } // Free textures marked for destruction **after** queue submit since they might still be used in the current frame. diff --git a/crates/egui-wgpu/src/capture.rs b/crates/egui-wgpu/src/capture.rs index 7eb1bd3ca..193cb4cce 100644 --- a/crates/egui-wgpu/src/capture.rs +++ b/crates/egui-wgpu/src/capture.rs @@ -212,10 +212,14 @@ impl CaptureState { let buffer_slice = buffer.slice(..); let mut pixels = Vec::with_capacity((tex_extent.width * tex_extent.height) as usize); - for padded_row in buffer_slice - .get_mapped_range() - .chunks(padding.padded_bytes_per_row as usize) - { + let mapped_range = match buffer_slice.get_mapped_range() { + Ok(range) => range, + Err(err) => { + log::error!("Failed to get mapped range for reading: {err}"); + return; + } + }; + for padded_row in mapped_range.chunks(padding.padded_bytes_per_row as usize) { let row = &padded_row[..padding.unpadded_bytes_per_row as usize]; for color in row.chunks(4) { pixels.push(epaint::Color32::from_rgba_premultiplied( diff --git a/crates/egui-wgpu/src/lib.rs b/crates/egui-wgpu/src/lib.rs index 10cd7cf04..d48198ed7 100644 --- a/crates/egui-wgpu/src/lib.rs +++ b/crates/egui-wgpu/src/lib.rs @@ -150,6 +150,7 @@ async fn request_adapter( // * fails if there's no software rasterizer available // * can achieve the same with `native_adapter_selector` force_fallback_adapter: false, + apply_limit_buckets: false, }) .await .inspect_err(|_err| { @@ -473,6 +474,7 @@ pub fn adapter_info_summary(info: &wgpu::AdapterInfo) -> String { subgroup_min_size, subgroup_max_size, transient_saves_memory, + limit_bucket, } = &info; // Example values: @@ -523,9 +525,10 @@ pub fn adapter_info_summary(info: &wgpu::AdapterInfo) -> String { } write!( summary, - ", transient_saves_memory: {transient_saves_memory}" + ", transient_saves_memory: {transient_saves_memory:?}" ) .ok(); + write!(summary, ", limit_bucket: {limit_bucket:?}").ok(); summary } diff --git a/crates/egui-wgpu/src/renderer.rs b/crates/egui-wgpu/src/renderer.rs index ff850af33..2ff9f7e4a 100644 --- a/crates/egui-wgpu/src/renderer.rs +++ b/crates/egui-wgpu/src/renderer.rs @@ -375,14 +375,14 @@ impl Renderer { vertex: wgpu::VertexState { entry_point: Some("vs_main"), module: &module, - buffers: &[wgpu::VertexBufferLayout { + buffers: &[Some(wgpu::VertexBufferLayout { array_stride: 5 * 4, step_mode: wgpu::VertexStepMode::Vertex, // 0: vec2 position // 1: vec2 texture coordinates // 2: uint color attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Uint32], - }], + })], compilation_options: wgpu::PipelineCompilationOptions::default() }, primitive: wgpu::PrimitiveState { diff --git a/crates/egui-wgpu/src/setup.rs b/crates/egui-wgpu/src/setup.rs index cf8b652c2..f2733a6e7 100644 --- a/crates/egui-wgpu/src/setup.rs +++ b/crates/egui-wgpu/src/setup.rs @@ -39,6 +39,7 @@ where } #[derive(Clone)] +#[expect(clippy::large_enum_variant)] pub enum WgpuSetup { /// Construct a wgpu setup using some predefined settings & heuristics. /// This is the default option. You can customize most behaviours overriding the diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index 0730f203b..1abf2d2fa 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -765,7 +765,7 @@ impl Painter { profiling::scope!("present"); // wgpu doesn't document where vsync can happen. Maybe here? let start = web_time::Instant::now(); - output_frame.present(); + render_state.queue.present(output_frame); vsync_sec += start.elapsed().as_secs_f32(); } diff --git a/crates/egui_demo_app/src/backend_panel.rs b/crates/egui_demo_app/src/backend_panel.rs index acd114ff4..4d6039a85 100644 --- a/crates/egui_demo_app/src/backend_panel.rs +++ b/crates/egui_demo_app/src/backend_panel.rs @@ -223,6 +223,7 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) { subgroup_min_size, subgroup_max_size, transient_saves_memory, + limit_bucket, } = &info; // Example values: @@ -276,7 +277,11 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) { ui.end_row(); } ui.label("Transient saves memory:"); - ui.label(format!("{transient_saves_memory}")); + ui.label(format!("{transient_saves_memory:?}")); + ui.end_row(); + + ui.label("Limit bucket:"); + ui.label(format!("{limit_bucket:?}")); ui.end_row(); }); }; diff --git a/crates/egui_kittest/src/texture_to_image.rs b/crates/egui_kittest/src/texture_to_image.rs index 5172555fe..289033fba 100644 --- a/crates/egui_kittest/src/texture_to_image.rs +++ b/crates/egui_kittest/src/texture_to_image.rs @@ -58,7 +58,9 @@ pub(crate) fn texture_to_image(device: &Device, queue: &Queue, texture: &Texture receiver.recv().unwrap().unwrap(); let buffer_slice = output_buffer.slice(..); - let data = buffer_slice.get_mapped_range(); + let data = buffer_slice + .get_mapped_range() + .expect("Failed to get mapped range"); let data = data .chunks_exact(buffer_dimensions.padded_bytes_per_row) .flat_map(|row| row.iter().take(buffer_dimensions.unpadded_bytes_per_row)) diff --git a/scripts/setup_web.sh b/scripts/setup_web.sh index 5ba11b665..0bd43e45a 100755 --- a/scripts/setup_web.sh +++ b/scripts/setup_web.sh @@ -10,6 +10,6 @@ rustup target add wasm32-unknown-unknown # For generating JS bindings: # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml -if ! cargo install --list | grep -q 'wasm-bindgen-cli v0.2.108'; then - cargo install --force --quiet wasm-bindgen-cli --version 0.2.108 --locked +if ! cargo install --list | grep -q 'wasm-bindgen-cli v0.2.126'; then + cargo install --force --quiet wasm-bindgen-cli --version 0.2.126 --locked fi