Skip to main content

SettingsFile

Struct SettingsFile 

Source
pub struct SettingsFile<T: Versioned + DeserializeOwned> { /* private fields */ }
Expand description

A reactive handle to a single typed file on disk.

Clone is cheap (an Rc bump). All clones share one in-memory projection and one I/O thread.

Implementations§

Source§

impl<T> SettingsFile<T>
where T: Versioned + Serialize + DeserializeOwned + Default + Clone + 'static,

Source

pub fn load( path: PathBuf, migrator: Migrator<T>, ) -> Result<Self, SettingsFileError>

Load the file from disk (running migrations) or initialize with T::default() if the file does not exist.

The initial read is lock-protected, exactly like every subsequent mutate / replace: a peer that is mid-write when this process starts up cannot hand us a torn read.

migrator is taken by value and retained for the lifetime of the handle: every later locked read re-runs it, since a peer might still be on an older on-disk schema at any point, not just at startup.

On a genuine parse failure (the bytes are not valid TOML at all, surviving MAX_READ_ATTEMPTS retries) the offending file is renamed to <path>.broken-<ts> and the returned SettingsFile starts from T::default() — the file really is corrupt, and the quarantine lets the next launch start clean instead of repeatedly failing to load it.

A SettingsFileError::Migrate or SettingsFileError::Io failure, by contrast, is not quarantined:

  • Migrate means the TOML parsed fine, but this build’s own Migrator chain doesn’t know how to bring it up to T::CURRENT_VERSION — the classic symptom of an older build opening a file a newer peer process already wrote in a newer schema. The file is not corrupt; renaming it would destroy that peer’s live, legitimate, still-in-use data.
  • Io means we couldn’t even read the file (permissions, a transient failure) — we never saw its content, so there is no basis at all for deciding it’s corrupt, and renaming (itself another I/O operation, on a path we just failed to read) would be reckless.

In both of those cases the handle falls back to T::default() for this session only, but the file on disk is left completely untouched. Use load_strict in tests that want to assert on the specific failure instead.

Source

pub fn load_strict( path: PathBuf, migrator: Migrator<T>, ) -> Result<Self, SettingsFileError>

Like load, but returns parse / migration errors instead of quarantining the file. Intended for tests that want to assert on a specific failure mode.

Source

pub fn borrow(&self) -> Ref<'_, T>

Borrow the current value. The returned Ref holds a RefCell guard; do not call any mutating method on this SettingsFile while a Ref is alive.

Source

pub fn snapshot(&self) -> T

Clone the current value out. Convenient when you don’t want to juggle a borrow.

Source

pub fn replace(&self, new: T) -> Result<(), SettingsFileError>

Replace the current value and persist it via a locked read-modify-write. The disk read is discarded — replace always wins over whatever was on disk — but the lock still serializes it against a concurrent peer write, and the fresh disk stamp is recorded so a subsequent reload doesn’t re-read our own write back in as if it were new. T::set_version(T::CURRENT_VERSION) is called so the version stamp is always coherent, even if the caller forgot.

Source

pub fn mutate<F: FnOnce(&mut T)>(&self, f: F) -> Result<(), SettingsFileError>

Mutate the current value in place and persist it via a locked read-modify-write: the file is re-read and re-migrated from disk under an exclusive lock before f is applied, so f always sees a fresh value — not this handle’s possibly-stale in-memory snapshot — and the result is written back atomically before the lock is released.

Takes f as FnOnce (not Fn) and imposes no Send bound on T: this write is synchronous on the calling thread, never replayed on a background worker, so there is no reason to tax every call site with a Send/Fn requirement it doesn’t need.

Source

pub fn reload_if_stale(&self) -> Result<bool, SettingsFileError>

Pick up a peer’s change: if the on-disk (mtime, len) differs from the last one this handle observed, re-read and re-migrate the file and refresh current. Returns whether a reload happened.

This is the cheap public probe — a stat, safe to call speculatively (e.g. on every focus-in, or on a timer). It does not perform the content-equality backstop that Reloadable::reload_from_disk adds on top (which additionally requires T: PartialEq); use that when a value-level “did anything actually change” guarantee is needed (e.g. driven by a file watcher, where a coincident stamp match must never be relied on alone).

Source

pub fn flush_now(&self) -> Result<(), SettingsFileError>

Synchronously write any pending payload to disk. A genuine no-op: mutate / replace already write synchronously on the calling thread, so nothing is ever pending — this type never registers with the shared debounced-write worker pool at all, so there is nothing to flush and nothing that can fail. Kept so callers that hold a SettingsFile alongside debounced types (SettingsStore, PersistedListModel) can flush everything uniformly without special-casing this type.

Source

pub fn path(&self) -> &Path

The path being written to.

Trait Implementations§

Source§

impl<T: Versioned + DeserializeOwned> Clone for SettingsFile<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Versioned + DeserializeOwned + Debug> Debug for SettingsFile<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Reloadable for SettingsFile<T>

The content-equality backstop on top of SettingsFile::reload_if_stale — see reload.rs’s module docs for the two-layer contract. Requires T: PartialEq (only for this impl block; every other SettingsFile method is unaffected), since this is the only place that needs to ask “is the freshly-read value actually different from what’s live.”

Source§

fn path(&self) -> &Path

The file this instance reads from and writes to. A watcher uses this to know which path to associate with which Reloadable handle.
Source§

fn reload_from_disk(&self) -> Result<bool, SettingsFileError>

Re-read the file from disk and push any genuinely new content into live signals/models. Read more

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for SettingsFile<T>

§

impl<T> !Send for SettingsFile<T>

§

impl<T> !Sync for SettingsFile<T>

§

impl<T> !UnwindSafe for SettingsFile<T>

§

impl<T> Freeze for SettingsFile<T>

§

impl<T> Unpin for SettingsFile<T>

§

impl<T> UnsafeUnpin for SettingsFile<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.