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 Constants§
Required Associated Types§
Sourcetype Error: Debug
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.
Sourcetype Legacy: Serialize + DeserializeOwned + Into<Self>
type Legacy: Serialize + DeserializeOwned + Into<Self>
Into<Setting>
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).
Sourcetype Setting: Serialize + DeserializeOwned + TryInto<(Version, Self), Error = Self::Error> + From<Self>
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<Self>
is intended to construct the latest version of the
configuration 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.
Provided Methods§
fn load(data_dir: &Path) -> Self
Sourcefn edit<R>(
&mut self,
data_dir: &Path,
f: impl FnOnce(&mut Self) -> Option<R>,
) -> Option<(R, Result<(), Error<Self>>)>
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
isErrorInternal::Integrity
, validation failed and the settings were not updated. - If
e
isErrorInternal::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.
fn get_path(data_dir: &Path) -> PathBuf
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.