use core::convert::Infallible; use crate::Append; /// `Persist` wraps a [`PersistBackend`] (`B`) to create a convenient staging area for changes (`C`) /// before they are persisted. /// /// Not all changes to the in-memory representation needs to be written to disk right away, so /// [`Persist::stage`] can be used to *stage* changes first and then [`Persist::commit`] can be used /// to write changes to disk. #[derive(Debug)] pub struct Persist { backend: B, stage: C, } impl Persist where B: PersistBackend, C: Default + Append, { /// Create a new [`Persist`] from [`PersistBackend`]. pub fn new(backend: B) -> Self { Self { backend, stage: Default::default(), } } /// Stage a `changeset` to be commited later with [`commit`]. /// /// [`commit`]: Self::commit pub fn stage(&mut self, changeset: C) { self.stage.append(changeset) } /// Get the changes that have not been commited yet. pub fn staged(&self) -> &C { &self.stage } /// Commit the staged changes to the underlying persistance backend. /// /// Returns a backend-defined error if this fails. pub fn commit(&mut self) -> Result<(), B::WriteError> { let mut temp = C::default(); core::mem::swap(&mut temp, &mut self.stage); self.backend.write_changes(&temp) } } /// A persistence backend for [`Persist`]. /// /// `C` represents the changeset; a datatype that records changes made to in-memory data structures /// that are to be persisted, or retrieved from persistence. pub trait PersistBackend { /// The error the backend returns when it fails to write. type WriteError: core::fmt::Debug; /// The error the backend returns when it fails to load changesets `C`. type LoadError: core::fmt::Debug; /// Writes a changeset to the persistence backend. /// /// It is up to the backend what it does with this. It could store every changeset in a list or /// it inserts the actual changes into a more structured database. All it needs to guarantee is /// that [`load_from_persistence`] restores a keychain tracker to what it should be if all /// changesets had been applied sequentially. /// /// [`load_from_persistence`]: Self::load_from_persistence fn write_changes(&mut self, changeset: &C) -> Result<(), Self::WriteError>; /// Return the aggregate changeset `C` from persistence. fn load_from_persistence(&mut self) -> Result; } impl PersistBackend for () { type WriteError = Infallible; type LoadError = Infallible; fn write_changes(&mut self, _changeset: &C) -> Result<(), Self::WriteError> { Ok(()) } fn load_from_persistence(&mut self) -> Result { Ok(C::default()) } }