Skip to main content

Module fs

Module fs 

Source
Expand description

Filesystem intrinsics for std/fs. pub, not private: its own doc comment explains the boundary it implements; nothing about that requires hiding the module itself. Branch std-fs-strings’s Task 3 and Task 4 (docs/superpowers/plans/2026-08-11-std-fs-strings.md) built most of this module, and branch byte-type’s own Task 4 later added read/write beside them, the same way this crate’s other modules build on task. Filesystem intrinsics for std/fs.

§The boundary this module implements

Nova has no out-parameters, so an intrinsic returns exactly one word — but read_to_string must convey a String and a two-field IoError. Rather than build a Nova sum and record here, which would put Nova value layout in Rust, the status code returned by each operation is the error kind, and payloads travel in the slots below. std/fs’s Nova wrappers map a status to an IoErrorKind and construct every Result and IoError themselves.

§Why SLOTS is a RefCell guarded with try_borrow_mut, not borrow_mut

Every function here is called from inside an async fn’s generated $poll, which has no landing pads (see nova_mir::async_lower’s module doc comment), so nothing here may panic. RefCell::borrow_mut panics on an already-outstanding borrow; try_borrow_mut cannot, so with_slot uses that instead and falls back to abort_with – which terminates without unwinding – on the contended case. Each slot still holds nothing more than a raw already-allocated pointer as a usize, with 0 meaning empty; the per-task table just adds one layer of indirection to reach it, keyed by slot_index.

stash itself is pub(crate): std/fs is not its only consumer. crates/nova-runtime/src/io.rs stashes the three standard streams’ payloads and write byte counts through this identical slot table, and crates/nova-runtime/src/crypto.rs stashes digests, HMAC tags and random bytes the same way, rather than either module owning a second one. take stays private (final review, M4) – io.rs’s own production code only ever stashes, and its tests reach take through the test-only take_for_test instead of take itself being widened for their sake.

§Why the pointer is GC-rooted while it sits in a slot

A slot is written by one intrinsic and read by the next, with Nova code in between. A conservative stack scan cannot see a pointer that lives only in a thread-local, so the object is registered with gc::add_root while stashed and released on take — the same balance task::spawn_internal and take_output_internal keep. Without it the payload could be collected between the two calls, which is why this does not merely rely on “no allocation happens in between”.

Constants§

ALREADY_EXISTS
CONNECTION_REFUSED
INTERRUPTED
INVALID_DATA
NOT_FOUND
OK
Status codes. 0 is success; every other value is an IoErrorKind.
OTHER
PERMISSION_DENIED
TIMED_OUT

Functions§

nova_rt_fs_create_dir⚠
Create the directory path. Its parent must exist; an existing path is ALREADY_EXISTS.
nova_rt_fs_create_dir_all⚠
Create the directory path, and any missing parent directories along the way. Unlike create_dir, an existing directory at path is success, not ALREADY_EXISTS – std::fs::create_dir_all’s own behaviour, carried through unchanged rather than papered over.
nova_rt_fs_exists⚠
Whether path exists. Cannot distinguish absent from unreadable, because nova-spec/20-STDLIB.md §5 gives exists a Bool return rather than a Result; that is the spec’s choice and is left alone.
nova_rt_fs_kind⚠
What path is: 0 = metadata unavailable (absent, or unreadable), 1 file, 2 directory.
nova_rt_fs_last_error_message
Take the pending error message.
nova_rt_fs_read⚠
Read path’s bytes. Returns a status; on OK the contents are waiting in nova_rt_fs_take_bytes.
nova_rt_fs_read_dir⚠
List path’s entry names, sorted. On OK the names are waiting in nova_rt_fs_take_string_array.
nova_rt_fs_read_to_string⚠
Read path as UTF-8. Returns a status; on OK the contents are waiting in nova_rt_fs_take_string.
nova_rt_fs_remove_dir_all⚠
Remove the directory path and everything under it.
nova_rt_fs_remove_file⚠
Remove the file path.
nova_rt_fs_take_bytes
Take the pending payload as Bytes. Returns an empty Bytes if nothing is pending, which a correct wrapper never asks for.
nova_rt_fs_take_string
Take the pending payload string. Returns an empty string if nothing is pending, which a correct wrapper never asks for.
nova_rt_fs_take_string_array
Take the array payload staged by a successful nova_rt_fs_read_dir.
nova_rt_fs_temp_dir
The OS temporary-directory path, per std::env::temp_dir().
nova_rt_fs_write⚠
Write content’s bytes to path, truncating an existing file.
nova_rt_fs_write_string⚠
Write content to path, truncating an existing file.