基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill rust-wasm命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
Practical guide for shipping Rust code as WebAssembly: small boundaries, typed interop, predictable memory, and measurable bundle size.
.wasm size after wasm-opt, not before.cfg(target_family = "wasm") for platform-specific code.wasm-bindgen on hot loops — pass whole buffers.rustup target add wasm32-unknown-unknown
cargo install wasm-pack
cargo new image-core --lib
# Cargo.toml
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
[dependencies.web-sys]
version = "0.3"
features = ["console", "Window", "Document", "HtmlCanvasElement"]
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct Filter {
strength: f32,
}
#[wasm_bindgen]
impl Filter {
#[wasm_bindgen(constructor)]
pub fn new(strength: f32) -> Self {
Self { strength }
}
pub fn apply_rgba(&self, pixels: &mut [u8]) {
for chunk in pixels.chunks_exact_mut(4) {
let gray = (chunk[0] as f32 * 0.299
+ chunk[1] as f32 * 0.587
+ chunk[2] as f32 * 0.114) as u8;
for channel in &mut chunk[..3] {
*channel = ((*channel as f32 * (1.0 - self.strength))
+ (gray * .strength)) ;
}
}
}
}
Use &mut [u8] for image/audio/data buffers. Avoid one exported call per pixel or row.
use serde::{Serialize, Deserialize};
use wasm_bindgen::prelude::*;
#[derive(Serialize, Deserialize)]
pub struct AnalysisResult {
pub mean: f64,
pub median: f64,
pub std_dev: f64,
pub count: usize,
}
#[wasm_bindgen]
pub fn analyze(data: &[f64]) -> JsValue {
let mean = data.iter().sum::<f64>() / data.len() as f64;
let result = AnalysisResult { mean, median: 0.0, std_dev: 0.0, count: data.len() };
serde_wasm_bindgen::to_value(&result).unwrap()
}
Use serde_wasm_bindgen for complex return types, but avoid on hot paths where the serialization overhead matters.
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn process_with_progress(
data: &[u8],
on_progress: &js_sys::Function,
) -> Result<(), JsValue> {
let total = data.len();
for (i, chunk) in data.chunks(1024).enumerate() {
// process chunk
let pct = (i as f64 / total as f64) * 100.0;
let this = JsValue::NULL;
let args = js_sys::Array::of1(&JsValue::from_f64(pct));
on_progress.call(&this, &args)?;
}
Ok(())
}
For hot paths, prefer passing a channel or buffer over function callbacks to avoid per-call overhead.
# Cargo.toml additional settings for threading
[package.metadata.wasm-pack.profile.release]
wasm-opt = false # wasm-opt breaks shared memory
// Enable shared memory in the module
#[wasm_bindgen]
pub fn init_pool(num_workers: usize) -> Result<(), JsValue> {
console_error_panic_hook::set_once();
// Use wasm-bindgen-rayon for thread pool
Ok(())
}
Threads require SharedArrayBuffer support, COOP/COEP headers, and wasm-opt compatibility flags.
#[cfg(debug_assertions)]
#[wasm_bindgen(start)]
pub fn init_debug() {
console_error_panic_hook::set_once();
}
[target.'cfg(debug_assertions)'.dependencies]
console_error_panic_hook = "0.1"
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(message: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
log(&format!("hello, {name}"));
}
Prefer explicit bindings over passing untyped JsValue everywhere.
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
#[wasm_bindgen]
pub async fn fetch_text(url: String) -> Result<String, JsValue> {
let window = web_sys::window().ok_or_else(|| JsValue::from_str("missing window"))?;
let response = JsFuture::from(window.fetch_with_str(&url)).await?;
let response: web_sys::Response = response.dyn_into()?;
let text = JsFuture::from(response.text()?).await?;
text.as_string().ok_or_else(|| JsValue::from_str("response text was not a string"))
}
Rust WASM memory (WASM linear memory) is separate from the JS heap:
wasm_bindgen copies strings and arrays by default.&[u8] / Vec<u8> for zero-copy buffer sharing where possible.free() on JS objects (they're JsValue with Drop) is automatic when the Rust wrapper goes out of scope.wasm-pack build --release --target web
wasm-opt -Oz -o pkg/optimized.wasm pkg/my_crate_bg.wasm
# Check size
ls -lh pkg/optimized.wasm
| Technique | Typical Savings |
|---|---|
opt-level = "z" | 15-25% |
| LTO + 1 codegen unit | 10-20% |
wasm-opt -Oz | 20-40% |
| Remove unused features | Variable |
wee_alloc (legacy) | Smaller binary, slower alloc |
Modern Rust uses the default allocator; wee_alloc is rarely needed with LTO.
// worker.rs — compiled separately as a dedicated wasm module
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn worker_entry() -> Result<(), JsValue> {
// Worker main loop — receives messages via browser postMessage
Ok(())
}
Workers cannot access the DOM (web_sys::window() returns None). Use postMessage for communication.
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 --release
# Run with wasmtime or wasmer
wasmtime run target/wasm32-wasip1/release/my-app.wasm
WASI gives you file I/O, clocks, and stdio — closer to a native binary than browser WASM.
// tests/web.rs
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn test_filter_applies() {
let filter = Filter::new(0.5);
let mut pixels = vec![100u8, 150, 200, 255, 50, 75, 100, 255];
filter.apply_rgba(&mut pixels);
assert!(pixels[0] < 100); // darkened
}
wasm-pack test --firefox # or --chrome, --safari, --node
wasm-pack test --headless
// Bad: thousands of boundary crossings.
#[wasm_bindgen]
pub fn set_pixel(x: u32, y: u32, r: u8, g: u8, b: u8) { /* ... */ }
// Good: one call over a whole buffer.
#[wasm_bindgen]
pub fn apply_image_filter(rgba: &mut [u8]) { /* ... */ }
// Bad: unchecked browser globals panic in workers or tests.
let document = web_sys::window().unwrap().document().unwrap();
// Good: model environment availability as Result.
let document = web_sys::window()
.and_then(|window| window.document())
.ok_or_else(|| JsValue::from_str("document unavailable"))?;
// Bad: re-serializing unchanged data on every frame.
let js_val = serde_wasm_bindgen::to_value(&my_data).unwrap();
// Good: cache the serialized form if data hasn't changed.
static CACHED: OnceLock<JsValue> = OnceLock::new();
// Bad: large data copied across boundary repeatedly.
// The input array is cloned into WASM memory every frame.
// Good: allocate once in WASM, pass the pointer, reuse the buffer.
// See wasm-bindgen's support for manual memory management.
wasm-pack build --release or equivalent.wasm-opt -Oz for size-sensitive web apps.serde_wasm_bindgen on hot paths unless ergonomics beat copy cost.wasm-bindgen-test.panic = "abort" in release profile.Source: adxptived/Rust-Skills — distributed by TomeVault.