Local storage
Persist small settings with day::prefs; store user documents and caches with day-part-fs.
Start with a working app. The facade’s default prefs feature supplies preferences; add
day-part-fs from the same revision for file operations. Neither store encrypts its contents.
Persist a setting
Create and bind the signal in the scope that should own persistence. This complete module also shows explicit writes when the app needs a success flag.
Complete module for src/storage.rs in the technical recipe harness.
The harness compiles this exact block; it is not a standalone app. Add the catalog entries below
to resource/locales/en/app.ftl and declare the module in src/lib.rs.
use crate::res;
use day::prelude::*;
pub fn saved_toggle() -> impl Piece {
let enabled = Signal::new(false);
day::prefs::bind("settings.reminders", enabled);
labeled(
res::str::storage_reminders(),
toggle(enabled).id(id!(storage_reminders)),
)
}
pub fn save_setting(value: bool) -> bool {
day::prefs::set("settings.reminders", &value.to_string())
}
pub async fn save_document(bytes: Vec<u8>) -> Result<(), day_part_fs::FsError> {
day_part_fs::write_future("notes/current.txt", bytes).await
}
storage_reminders = Reminders
Preference keys and downloaded-file paths are application identifiers, not bundled resources.
The bytes passed to save_document are user data. Call the async function inside day::task and
handle its result there; use a generated localized message for any failure shown to the user.
bind reads a stored value immediately and uses it only if FromStr succeeds. It watches later
changes and serializes them with ToString; it does not save the initial default merely because
you created the binding. Its watch ends with the current scope, and it discards write failures.
Use set directly when a failed save must be reported. get returns None for absence or an
unavailable store; an empty stored value is Some(""). remove returns false for absence or a
failed removal, so it cannot distinguish those cases.
With the optional model feature, day::prefs::bind_json persists a model store. Navigation’s
.restore(key) uses the installed nav store. See model state and
navigation for these separate contracts.
Read, list, and remove files
Each operation has blocking, callback (*_async), and future (*_future) forms. Use futures
under day::task to resume on the UI thread; callbacks require Send and must deliver UI data
through a Setter. Blocking forms exist on web but return FsError::Unsupported.
| Operation | Contract |
|---|---|
read_future(path) | Returns the whole file as Vec<u8> or an error |
write_future(path, bytes) | Creates parents; creates or truncates the file; no atomic-replacement guarantee |
remove_future(path) | Removes a file or empty directory; missing paths return NotFound |
list_future(dir) | Sorted immediate names, directories suffixed /; "" means root; a missing directory is empty |
open_read(path) | Native-only, blocking, seekable std::fs::File for readers that must avoid whole-file buffers |
Paths must be relative, with no colon, leading separator, empty segment, . or .. segment.
The root exception applies only to listing. These lexical checks are not an OS sandbox or
protection against symlinks planted by another actor. FsError is non-exhaustive: handle
NotFound, BadPath, Io, Unsupported, and a fallback arm when matching variants.
Dropping an fs future stops listening; native jobs are detached blocking-pool work and may still write the file. Do not describe cancellation as undoing an accepted save.
Resolve storage locations
On native targets, DAY_DATA_DIR overrides the app-data root. Without it, the implementation
uses the platform data directory plus day; file operations add day-fs/. This fallback is
shared naming, not proof of isolation between unrelated apps. A host must provide an app-specific
root when isolation is required. Mobile hosts supply their private files directory.
| Target | Fallback before day/day-fs/ |
|---|---|
| macOS / iOS | ~/Library/Application Support/ within the process’s home/container |
| Linux | $XDG_DATA_HOME/, otherwise ~/.local/share/ |
| Windows | %APPDATA%/ |
| web-dom | Origin Private File System; no native path |
Web preferences use localStorage; files use OPFS. Browser storage can be unavailable or fail,
and this API provides no durability promise against browser eviction. Unknown native hosts can
return Unsupported. Keep credentials in a separately integrated secure store.
Verify persistence
Compile the module with the recipe harness.
In the app, change the toggle, restart, and verify restoration. Exercise unavailable storage and
a failed write separately. For isolated tests, enable the prefs memory feature and use a
repository-local DAY_DATA_DIR; these controls avoid touching real user settings.
Source evidence: prefs API and bind implementation, fs API, and native root and IO behavior. Detailed lookup: prefs, files, and async lifetime.