linera_persistent/
lib.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5This crate handles persisting data types to disk with a variety of backends.
6*/
7
8#![allow(async_fn_in_trait)]
9
10cfg_if::cfg_if! {
11    if #[cfg(with_indexed_db)] {
12        pub mod indexed_db;
13        pub use indexed_db::IndexedDb;
14    }
15}
16
17cfg_if::cfg_if! {
18    if #[cfg(feature = "fs")] {
19        pub mod file;
20        pub use file::File;
21    }
22}
23
24pub mod memory;
25use std::ops::Deref;
26
27pub use memory::Memory;
28
29/// The `Persist` trait provides a wrapper around a value that can be saved in a
30/// persistent way. A minimal implementation provides an `Error` type, a `persist`
31/// function to persist the value, and an `as_mut` function to get a mutable reference to
32/// the value in memory.
33#[cfg_attr(not(web), trait_variant::make(Send))]
34pub trait Persist: Deref {
35    type Error: std::error::Error + Send + Sync + 'static;
36
37    /// Gets a mutable reference to the value. This is not expressed as a
38    /// [`DerefMut`](std::ops::DerefMut) bound because it is discouraged to use this
39    /// function! Instead, use `mutate`.
40    fn as_mut(&mut self) -> &mut Self::Target;
41
42    /// Saves the value to persistent storage.
43    async fn persist(&mut self) -> Result<(), Self::Error>;
44
45    /// Takes the value out.
46    fn into_value(self) -> Self::Target
47    where
48        Self::Target: Sized;
49}
50
51pub trait PersistExt: Persist {
52    /// Applies a mutation to the value, persisting when done.
53    async fn mutate<R>(
54        &mut self,
55        mutation: impl FnOnce(&mut Self::Target) -> R,
56    ) -> Result<R, Self::Error>;
57}
58
59impl<T: Persist> PersistExt for T {
60    async fn mutate<R>(
61        &mut self,
62        mutation: impl FnOnce(&mut Self::Target) -> R,
63    ) -> Result<R, Self::Error> {
64        let output = mutation(self.as_mut());
65        self.persist().await?;
66        Ok(output)
67    }
68}