pub trait EditableSetting: Clone + Default {
    type Error: Debug;
    type Legacy: Serialize + DeserializeOwned + Into<Self>;
    type Setting: Serialize + DeserializeOwned + TryInto<(Version, Self), Error = Self::Error> + From<Self>;

    const FILENAME: &'static str;

    // Provided methods
    fn load(data_dir: &Path) -> Self { ... }
    fn edit<R>(
        &mut self,
        data_dir: &Path,
        f: impl FnOnce(&mut Self) -> Option<R>
    ) -> Option<(R, Result<(), Error<Self>>)> { ... }
    fn get_path(data_dir: &Path) -> PathBuf { ... }
}

Required Associated Types§

source

type Error: Debug

Please use this error sparingly, since we ideally want to preserve forwards compatibility for all migrations. In particular, this error should be used to fail validation of the original settings file that cannot be caught with ordinary parsing, rather than used to signal errors that occurred during migrations.

The best error type is Infallible.

source

type Legacy: Serialize + DeserializeOwned + Into<Self>

Into is expected to migrate directly to the latest version, which can be implemented using “chaining”. The use of Into here rather than TryInto is intended (together with the expected use of chaining) to prevent migrations from invalidating old save files without warning; there should always be a non-failing migration path from the oldest to latest format (if the migration path fails, we can panic).

source

type Setting: Serialize + DeserializeOwned + TryInto<(Version, Self), Error = Self::Error> + From<Self>

TryInto<(Version, Self)> is expected to migrate to the latest version from any older version, using “chaining” (see super::banlist for examples).

From is intended to construct the latest version of the configuratino file from Self, which we use to save the config file on migration or modification. Note that it should always be the case that if x is constructed from any of Self::clone, Self::default, or Setting::try_into, then Setting::try_from(Self::into(x)).is_ok() must be true!

The error should be used to fail validation of the original settings file that cannot be caught with parsing. If we can possibly avoid it, we should not create errors in valid settings files during migration, to ensure forwards compatibility.

Required Associated Constants§

source

const FILENAME: &'static str

Provided Methods§

source

fn load(data_dir: &Path) -> Self

source

fn edit<R>( &mut self, data_dir: &Path, f: impl FnOnce(&mut Self) -> Option<R> ) -> Option<(R, Result<(), Error<Self>>)>

If the result of calling f is None,we return None (this constitutes an early return and lets us abandon the in-progress edit). For example, this can be used to avoid adding a new ban entry if someone is already banned and the user didn’t explicitly specify that they wanted to add a new ban record, even though it would be completely valid to attach one.

Otherwise (the result of calling f was Some(r)), we always return Some((r, res)), where:

If res is Ok(()), validation succeeded for the edited, and changes made inside the closure are applied both in memory (to self) and atomically on disk.

Otherwise (res is Err(e)), some step in the edit process failed. Specifically:

  • If e is Integrity, validation failed and the settings were not updated.
  • If e is Io, validation succeeded and the settings were updated in memory, but they could not be saved to storage (and a warning was logged). The reason we return an error even though the operation was partially successful is so we can alert the player who ran the command about the failure, as they will often be an administrator who can usefully act upon that information.
source

fn get_path(data_dir: &Path) -> PathBuf

Object Safety§

This trait is not object safe.

Implementors§