-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Browser-Specific Standard Library Implementations
Problem
naml's standard library crates are built on native OS APIs (libc, std::fs, std::net, tokio, etc.) that don't exist in browser WASM environments. For naml to run in browsers, each std module needs a browser-specific implementation using Web APIs, selectable via the #[platforms(browser)] attribute system.
Current Std Library Platform Analysis
Already WASM-Compatible (no changes needed)
These crates use pure Rust with no OS dependencies:
naml-std-core— HeapHeader, NamlString, NamlStruct, refcountingnaml-std-random— Can usegetrandomcrate (supports wasm32)naml-std-datetime— Needsjs_sys::Datefor browser, otherwise pure Rustnaml-std-metrics—performance.now()viaweb_sysfor browser timingnaml-std-strings— Pure string operationsnaml-std-collections— Pure data structure operationsnaml-std-path— Pure path manipulationnaml-std-testing— Pure assertion logicnaml-std-encoding— JSON/TOML/YAML/Base64/Hex are pure Rust
Need Browser Implementations
Each of these needs a #[platforms(browser)] alternative:
| Module | Native API | Browser API | Complexity |
|---|---|---|---|
std::crypto |
RustCrypto crates | WebCrypto API (crypto.subtle) |
Medium |
std::net::http |
Hyper + Tokio | Fetch API (fetch()) |
Medium |
std::fs |
std::fs + libc |
OPFS (Origin Private File System) | High |
std::threads |
OS threads (M:N scheduler) | Web Workers + SharedArrayBuffer |
Very High |
std::io |
libc terminal control | DOM Console API | Low |
Native-Only (no browser equivalent)
These modules have no meaningful browser equivalent and should be excluded:
std::process— fork/exec/signals don't exist in browsersstd::os— uid/gid/hostname are OS conceptsstd::sqlite— Could use sql.js/wa-sqlite, but very different API surface
Proposed Browser Implementations
1. std::crypto → WebCrypto API
// Same naml API, different implementation
var hash: bytes = sha256(data); // crypto.subtle.digest("SHA-256", data)
var mac: bytes = hmac_sha256(key, data); // crypto.subtle.sign("HMAC", key, data)
var key: bytes = pbkdf2_sha256(...); // crypto.subtle.deriveBits("PBKDF2", ...)
var rand: bytes = random_bytes(32); // crypto.getRandomValues(new Uint8Array(32))
Implementation: Import WebCrypto functions via wasm-bindgen. Note that WebCrypto is async — naml's sync API would need to use wasm-bindgen-futures or block on promises.
Challenge: WebCrypto's crypto.subtle.digest() returns a Promise<ArrayBuffer>, but naml's sha256() is synchronous. Options:
- Use synchronous WebCrypto where available (only
getRandomValuesis sync) - Compile RustCrypto to WASM directly (works, just larger binary)
- Make naml's crypto API async-aware on browser target
2. std::net::http → Fetch API
// Same naml API
var resp: response = http_get("https://api.example.com/data", none);
Native: Hyper + Tokio (current implementation)
Browser: fetch() API via web_sys::window().fetch()
Implementation:
wasm-bindgen+web-syswithfetchfeature- Map naml's
request/responsestructs toweb_sys::Request/web_sys::Response - Handle async nature: Fetch returns Promises, needs
wasm-bindgen-futures
HTTP Server: Not applicable in browser — serve() should be platform-gated to native/server only.
3. std::fs → Origin Private File System (OPFS)
// Same naml API
var content: string = read_file("data/config.toml");
write_file("output/result.txt", content);
Browser: Use OPFS (navigator.storage.getDirectory())
- Provides a sandboxed filesystem in the browser
- Supports read/write/delete operations
- Async API — same challenge as WebCrypto
Limitations:
- No access to real filesystem (sandboxed)
- Different path semantics (no absolute paths)
- Size quotas apply
4. std::threads → Web Workers
This is the most complex adaptation.
Native: Custom M:N scheduler with OS threads, channels, spawn blocks
Browser: Web Workers with postMessage for communication
Challenges:
- Web Workers are isolated — no shared memory by default
SharedArrayBufferenables shared memory but requires COOP/COEP headers- naml's channel semantics need mapping to
postMessage/MessageChannel - naml's
spawn {}blocks capture variables — Web Workers can't share JS heap objects - Atomics (
std::sync::atomic) work withSharedArrayBufferin WASM
Possible approaches:
- SharedArrayBuffer + Atomics: Closest to native semantics, requires secure context
- postMessage serialization: Simpler but no shared state, channels become message passing
- Single-threaded async: Use
Promise/asyncinstead of real parallelism
5. std::io → Console API
// Native: libc terminal control
// Browser: console.log, prompt()
println("Hello"); // console.log("Hello")
var input: string = readln(); // prompt("") or custom DOM input
Simple mapping — mostly console.log/console.error. Interactive input (read_key, readln) would need DOM integration.
Architecture: How to Structure Platform-Specific Code
Option A: Conditional compilation in Rust (recommended for std crates)
#[cfg(not(target_arch = "wasm32"))]
mod native;
#[cfg(target_arch = "wasm32")]
mod browser;
// Re-export the correct implementation
#[cfg(not(target_arch = "wasm32"))]
pub use native::*;
#[cfg(target_arch = "wasm32")]
pub use browser::*;Option B: Separate crates
std/naml-std-crypto/ → Pure Rust (works everywhere)
std/naml-std-crypto-browser/ → WebCrypto wasm-bindgen wrapper
Option C: Feature flags
[features]
native = ["tokio", "hyper"]
browser = ["wasm-bindgen", "web-sys", "js-sys"]Files to Create
For each browser-adapted module:
std/naml-std-<module>/src/browser.rs— Browser-specific implementation- Or
std/naml-std-<module>-browser/— Separate browser crate
Files to Modify
std/naml-std-crypto/Cargo.toml— Addwasm-bindgen,web-sysas optional depsstd/naml-std-net/Cargo.toml— Addweb-sysfetch featurestd/naml-std-fs/Cargo.toml— Add OPFS supportnamlc/src/codegen/cranelift/mod.rs— Register browser-specific runtime symbolsnamlc/src/typechecker/mod.rs— Platform-aware function registration
Acceptance Criteria
-
std::cryptofunctions work in browser WASM using WebCrypto or compiled RustCrypto -
std::net::httpclient functions work in browser using Fetch API -
std::fsprovides sandboxed file operations via OPFS in browser -
std::threads::spawnmaps to Web Workers (or provides clear async alternative) -
std::io::printlnmaps toconsole.login browser - Native-only modules (
std::process,std::os) produce clear compile errors when targeting browser - Same naml source code works on both native and browser with no changes (where APIs overlap)
Depends On
- AOT Compilation Backend (need to compile to WASM)
naml build --target browser(need build pipeline)- Platform Attribute Enforcement (need to select correct implementation)
Blocks
- Running naml applications in web browsers