wasm_safe_thread 0.1.1

Cross-platform std::thread + std::sync replacement for native and wasm32.
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Build Commands

```bash
scripts/check_all          # Run all checks: fmt, check, clippy, tests, docs
scripts/tests              # Run tests (native + wasm32)
scripts/check              # Compile check (native + wasm32)
scripts/clippy             # Clippy (native + wasm32)
scripts/docs               # Build docs (native + wasm32)
scripts/fmt                # Check formatting

scripts/native/tests       # Native tests only
scripts/wasm32/tests       # WASM tests only (requires nightly)
```

Platform-specific scripts are in `scripts/native/` and `scripts/wasm32/`. The wasm32 scripts source `scripts/wasm32/_env` which sets up required RUSTFLAGS from `.cargo/config.toml`.

## Architecture

This crate provides a unified `std::thread`-like API that works on both native and WASM platforms. The core abstraction is a backend module pattern:

- `src/lib.rs` - Public API that delegates to the active backend
- `src/stdlib.rs` - Native backend (wraps `std::thread`)
- `src/wasm.rs` - WASM backend (Web Workers via `wasm-bindgen`)
- `src/wasm/wasm_utils.rs` - Low-level JS utilities (atomics, parking, environment detection)
- `src/hooks.rs` - Global spawn hook registry (runs callbacks at thread start)
- `src/test_executor.rs` - Test infrastructure with `async_test!` macro

Backend selection at compile time:
```rust
#[cfg(not(target_arch = "wasm32"))]
use stdlib as backend;
#[cfg(target_arch = "wasm32")]
use wasm as backend;
```

## Key Types

Both backends implement the same types with matching APIs:
- `Thread`, `ThreadId` - Thread handle and identifier
- `JoinHandle<T>` - Handle for joining spawned threads
- `Builder` - Thread configuration builder
- `LocalKey<T>` - Thread-local storage key

## WASM Implementation Details

The WASM backend spawns Web Workers with inline JavaScript (via `wasm_bindgen(inline_js)`). Key mechanisms:

- **Worker spawning**: `spawn_with_shared_module()` creates workers that share the WASM module and memory
- **Result passing**: Uses `wasm_safe_mutex::mpsc` channels for cross-thread communication
- **Exit coordination**: `exit_state` is a reference-counted atomic `[exit_code, ref_count]` that tracks worker completion
- **Panic handling**: Custom panic hook sends error through channel before abort
- **Async task tracking**: `task_begin()`/`task_finished()` track pending `spawn_local` tasks; worker waits for all to complete

Main thread restrictions (browser):
- `join()` panics - use `join_async()` instead
- `park()`/`park_timeout()` unavailable - `Atomics.wait` doesn't work on main thread

## Testing

Use the `async_test!` macro for cross-platform async tests:
```rust
crate::async_test! {
    async fn my_test() {
        let handle = spawn(|| 42);
        let result = handle.join_async().await.unwrap();
        assert_eq!(result, 42);
    }
}
```

This expands to:
- Native: `#[test]` with `test_executor::spawn()` polling loop
- WASM: `#[wasm_bindgen_test]` async test

Tests that need synchronous `join()` on WASM must run in a worker context (not main thread).