ashlar-fs 0.1.0

Files and settings: app dirs, durable atomic writes, keyed settings, recent files
Documentation

ashlar-fs

Files and settings for ashlar apps. Headless, no UI dependencies, builds for wasm32-unknown-unknown.

Item What it does
AppDirs::new(qualifier, org, app) Config, data, cache and logs directories where each OS expects them (via the directories crate). ASHLAR_DIRS_ROOT=/some/dir puts all four under one folder (tests, portable installs). AppDirs::under(root) does the same in code.
AppDirs::data_only(app, override_env) The conventional flat per-app data folder: ~/Library/Application Support/<App>, %APPDATA%\<App>, $XDG_DATA_HOME/<app> or ~/.local/share/<app>. The app's own override variable wins; ASHLAR_DIRS_ROOT does not move it. dirs::data_dir_for(os, app, override_env, lookup) is the pure core, for tests.
atomic_write(path, bytes) Durable replace: hidden temp file in the same directory, write, fsync, rename over the target, fsync the directory (Unix). On failure the temp file is removed and the old file is untouched. Follows symlinks, keeps permissions. atomic_write_with(path, |file| ...) streams instead of buffering.
ConfigStore Named text blobs (settings.json, keymap.json). DirConfig (a folder, atomic writes) and MemoryConfig. Names that climb out of the store (.., absolute) are refused.
FileOps Path-based read / atomic write / remove / list, for autosave and recovery. StdFiles and MemFiles. A browser (OPFS) backend implements the same trait.
Settings Keyed JSON: get::<T>, get_or, set, remove, keys. File shape {"schema_version": N, "values": {...}} with a migration chain. Saves after a quiet period (tick(now)) or at once (flush()). A corrupt file is moved to <name>.corrupt; a file from a newer schema is read but never overwritten.
RecentFiles MRU list: cap, dedupe (lexically normalized paths), prune(exists), load/store through Settings.

Clock

Settings::tick takes a monotonic Duration from the caller instead of reading Instant, so it behaves the same on the web (where Instant::now() panics) and is deterministic in tests.

Durability notes

  • The parent directory must exist (StdFiles::write creates it).
  • Windows has no directory fsync; the rename goes through MoveFileExW, which NTFS journals.
  • Leftover temp files from a crash mid-save are named .<name>.<pid>-<n>.tmp; atomic::is_temp_name recognises them and StdFiles::list hides them.