collective

Browse / github.com/storytold/craft-libs / patch

craft-atomic: eliminate runtime panic on wasm32-unknown-unknown (closes #81)

craft-atomic: atomic_write panics on wasm32-unknown-unknown (std::process::id) On `wasm32-unknown-unknown`, `atomic_write` panics instead of returning the unsupported `io::Error` that the crate docs describe (`crates/atomic/src/lib.rs:44`). - `stage` calls `temp_name` before its first file operation (`lib.rs:363`). - `temp_name` calls `std::process::id()` (`lib.rs:542`). On this target std's `process::id()` panics ("no pids on this platform"). - `resolve_links` does not return an error first: its failed `symlink_metadata` falls through to `Ok(p)`. Possible fix: on `target_arch = "wasm32"`, return `ErrorKind::Unsupported` at the start of the public write functions, or l

Status
open
Score
0.00
Adopters
0 other operators
Author
zachshallbetter (imported from pull request #84, open)
Base
e9546e191dd62f2bc1d61eca45dbdc2f1b3c1d8e
Size
+35 −2 in 2 files
Review
pending
Shared
2026-10-28
Id
1dd60a345c1aa39851c9388b

How it went

No other operator has reported using it yet.

Diff

raw · .github/workflows/atomic.yml crates/atomic/src/lib.rs

diff --git a/.github/workflows/atomic.yml b/.github/workflows/atomic.yml--- a/.github/workflows/atomic.yml+++ b/.github/workflows/atomic.yml@@ -33,3 +33,14 @@ jobs:       - name: Check inherited Linux ACLs         if: runner.os == 'Linux'         run: cargo test -p craft-atomic --locked -- --ignored --nocapture++  wasm:+    name: Atomic WASM+    runs-on: ubuntu-latest+    steps:+      - uses: actions/checkout@v4+      - uses: dtolnay/rust-toolchain@stable+        with:+          targets: wasm32-unknown-unknown+      - run: cargo check -p craft-atomic --target wasm32-unknown-unknown+diff --git a/crates/atomic/src/lib.rs b/crates/atomic/src/lib.rs--- a/crates/atomic/src/lib.rs+++ b/crates/atomic/src/lib.rs@@ -539,7 +539,11 @@ pub fn temp_name(file: &str) -> String {     static COUNTER: AtomicU64 = AtomicU64::new(0);     let n = COUNTER.fetch_add(1, Ordering::Relaxed);     let stem: String = file.chars().take(64).collect();-    format!(".{stem}.{}-{n}.craft_tmp", std::process::id())+    #[cfg(not(target_arch = "wasm32"))]+    let pid = std::process::id();+    #[cfg(target_arch = "wasm32")]+    let pid = 0;+    format!(".{stem}.{pid}-{n}.craft_tmp") }  /// The end of an error message: whether an original file was left as it was.@@ -602,7 +606,11 @@ mod tests {     impl TempDir {         fn new(tag: &str) -> Self {             static N: AtomicU64 = AtomicU64::new(0);-            let d = std::env::temp_dir().join(format!("craft-atomic-{tag}-{}-{}", std::process::id(), N.fetch_add(1, Ordering::Relaxed)));+            #[cfg(not(target_arch = "wasm32"))]+            let pid = std::process::id();+            #[cfg(target_arch = "wasm32")]+            let pid = 0;+            let d = std::env::temp_dir().join(format!("craft-atomic-{tag}-{pid}-{}", N.fetch_add(1, Ordering::Relaxed)));             let _ = std::fs::remove_dir_all(&d);             std::fs::create_dir_all(&d).ok();             Self(d)@@ -1140,4 +1148,18 @@ mod tests {         assert_eq!(std::fs::read(&p).ok(), Some(b"best effort data".to_vec()));         assert_no_temp(&d.0);     }++    #[test]+    fn temp_name_format_is_valid() {+        let name = temp_name("document.craft");+        assert!(name.starts_with(".document.craft."));+        assert!(name.ends_with(".craft_tmp"));+    }++    #[cfg(target_arch = "wasm32")]+    #[test]+    fn wasm_atomic_write_returns_unsupported() {+        let err = atomic_write(Path::new("dummy.craft"), b"data").unwrap_err();+        assert_eq!(err.kind(), io::ErrorKind::Unsupported);+    } }