Struct PersistedLazy

Source
pub struct PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey, C: PersistedContainer<Value = K::Value>,
{ /* private fields */ }
Expand description

Similar to Persisted, but the value that’s sent to the store is not the same as the value stored in memory. Instead, the value is computed at save time by PersistedContainer::get_to_persist. Similarly, the persisted value that’s loaded at initialization isn’t stored directly in the container. Instead, PersistedContainer::restore_persisted determines how to initialize state based on it.

This is useful if the value you want to store is some derivation of the value you keep in memory. For example, storing which item in a list is selected: if you store the index of the selected item in memory but want to persist the ID of the selected item so it’s resilient to re-ordering, you can use this.

§Generic Params

  • S: The backend type used to persist data. While we don’t need access to an instance of the backend, we do need to know its type so we can access its static functions on setup/save.
  • K: The type of the persistence key
  • C: The type of the wrapping container (see PersistedContainer). The type of the container’s persisted value must match the expected value for the key. In other words, K::Value must equal C::Value.

§Accessing

The inner value can be accessed immutably via Deref. To get mutable access, use PersistedLazy::get_mut. This wrapper method returns a guard that implements DerefMut (similar to RefMut or MutexGuard from std, without the internal mutability). When your mutable access is complete, this wrapper will be dropped and the value will be persisted to the store only if it changed (according to its PartialEq impl).

§Cloning

This type intentionally does not implement Clone. Cloning would result in two containers with the same key. Whenever a modification is made to one it will overwrite the persistence slot. It’s unlikely this is the desired behavior, and therefore is not provided.

§Example

use persisted::{
    PersistedContainer, PersistedKey, PersistedLazy, PersistedStore,
};
use core::cell::Cell;

/// Persist just the stored ID
#[derive(Default)]
struct Store(Cell<Option<PersonId>>);

impl Store {
    thread_local! {
        static INSTANCE: Store = Default::default();
    }
}

impl PersistedStore<SelectedIdKey> for Store {
    fn load_persisted(_key: &SelectedIdKey) -> Option<PersonId> {
        Self::INSTANCE.with(|store| store.0.get())
    }

    fn store_persisted(_key: &SelectedIdKey, value: &PersonId) {
        Self::INSTANCE.with(|store| store.0.set(Some(*value)))
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct PersonId(u64);

#[derive(Clone, Debug)]
#[allow(unused)]
struct Person {
    id: PersonId,
    name: String,
    age: u32,
}

#[derive(Debug, PersistedKey)]
#[persisted(PersonId)]
struct SelectedIdKey;

/// A list of items, with one item selected
struct SelectList {
    values: Vec<Person>,
    selected_index: usize,
}

impl SelectList {
    fn selected(&self) -> &Person {
        &self.values[self.selected_index]
    }
}

impl PersistedContainer for SelectList {
    type Value = PersonId;

    fn get_to_persist(&self) -> Self::Value {
        self.selected().id
    }

    fn restore_persisted(&mut self, value: Self::Value) {
        // Find selected person by ID
        self.selected_index = self
            .values
            .iter()
            .enumerate()
            .find(|(_, person)| person.id == value)
            .map(|(i, _)| i)
            .unwrap_or_default();
    }
}

let person_list = vec![
    Person {
        id: PersonId(23089),
        name: "Fred".into(),
        age: 17,
    },
    Person {
        id: PersonId(28833),
        name: "Susan".into(),
        age: 29,
    },
    Person {
        id: PersonId(93383),
        name: "Ulysses".into(),
        age: 40,
    },
];

let mut people = PersistedLazy::<Store, _, _>::new(
    SelectedIdKey,
    SelectList {
        values: person_list.clone(),
        selected_index: 0,
    },
);
people.get_mut().selected_index = 1;
assert_eq!(people.selected().id.0, 28833);

let people = PersistedLazy::<Store, _, _>::new(
    SelectedIdKey,
    SelectList {
        values: person_list,
        selected_index: 0,
    },
);
// The previous value was restored
assert_eq!(people.selected_index, 1);
assert_eq!(people.selected().id.0, 28833);

Implementations§

Source§

impl<S, K, C> PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey, C: PersistedContainer<Value = K::Value>,

Source

pub fn new(key: K, container: C) -> Self

Initialize a given container whose value will lazily be loaded and persisted. If a persisted value is available in the store, it will be loaded and used to initialize the container via PersistedContainer::restore_persisted.

Source

pub fn new_default(key: K) -> Self
where C: Default,

Initialize a new default container whose value will lazily be loaded and persisted. If a persisted value is available in the store, it will be loaded and used to initialize the container via PersistedContainer::restore_persisted.

Source

pub fn get_mut(&mut self) -> PersistedLazyRefMut<'_, S, K, C>
where K::Value: PartialEq,

Get a mutable reference to the value. This is wrapped by a guard, so that after mutation when the guard is dropped, the value can be persisted. PersistedStore::store_persisted will only be called if the persisted value actually changed, hence the K::Value: PartialEq bound. This means PersistedContainer::get_to_persist will be called after event mutable access, but the value will only be written to the store when it’s been modified.

Trait Implementations§

Source§

impl<S, K, C> Debug for PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey + Debug, C: PersistedContainer<Value = K::Value> + Debug, K::Value: Debug,

Source§

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

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

impl<S, K, C> Default for PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey + Default, C: PersistedContainer<Value = K::Value> + Default,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<S, K, C> Deref for PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey, C: PersistedContainer<Value = K::Value>,

Source§

type Target = C

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<S, K, C> Display for PersistedLazy<S, K, C>
where S: PersistedStore<K>, K: PersistedKey, C: PersistedContainer<Value = K::Value> + Display,

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<S, K, C> Freeze for PersistedLazy<S, K, C>
where K: Freeze, C: Freeze, <K as PersistedKey>::Value: Freeze,

§

impl<S, K, C> RefUnwindSafe for PersistedLazy<S, K, C>

§

impl<S, K, C> Send for PersistedLazy<S, K, C>
where K: Send, C: Send, S: Send, <K as PersistedKey>::Value: Send,

§

impl<S, K, C> Sync for PersistedLazy<S, K, C>
where K: Sync, C: Sync, S: Sync, <K as PersistedKey>::Value: Sync,

§

impl<S, K, C> Unpin for PersistedLazy<S, K, C>
where K: Unpin, C: Unpin, S: Unpin, <K as PersistedKey>::Value: Unpin,

§

impl<S, K, C> UnwindSafe for PersistedLazy<S, K, C>

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> 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<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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.