7个不稳定版本 (3个重大变更)

新功能 0.3.0 2024年8月17日
0.2.2 2024年8月9日
0.1.1 2024年6月21日
0.0.1 2024年6月14日

#1531 in 数据库接口

Download history 191/week @ 2024-06-14 326/week @ 2024-06-21 11/week @ 2024-06-28 19/week @ 2024-07-05 1/week @ 2024-07-12 20/week @ 2024-07-19 79/week @ 2024-07-26 227/week @ 2024-08-02 198/week @ 2024-08-09 174/week @ 2024-08-16

每月686次下载
2个crate中使用(通过slumber_tui

MIT许可协议

31KB
287

持久化

Test CI crates.io docs.rs

persisted是一个Rust库,它使得保存任意程序状态变得简单快捷。其简单灵活的设计意味着你可以自己选择数据存储方案。你告诉persisted如何保存数据以及你想保存什么,然后它会处理其余的事情。

示例请参阅examples/目录或文档


lib.rs:

persisted是一个库,用于在程序中持久化任意值,以便稍后轻松恢复。该库的主要目标是

  • 明确性:你定义了要持久化的内容及其类型
  • 易用性:薄薄的包装使持久化值变得容易
  • 灵活性:persisted与数据存储无关;你可以使用任何你想要的持久化方案,包括数据库、键值存储等。

persisted最初是为Slumber设计的,这是一个TUI HTTP客户端。因此,它的主要用例是在用户界面会话之间持久化值。尽管如此,它非常灵活,可以在任何类型的上下文中持久化任何类型的值。支持no_std意味着它甚至可以在嵌入式环境中使用。

概念

persisted充当你的值和你的数据存储之间的中间人。你定义你的数据结构和数据应该如何保存,persisted确保数据被适当地加载和存储。关键概念包括

  • 数据包装器:[Persisted]和[PersistedLazy]
    • 这些将你的数据包装起来,以自动从存储中恢复和保存值
  • 数据存储:任何实现了[PersistedStore]的实现者
  • 键:存储中值的唯一标识符。每个持久化值都必须有自己的键。键类型必须实现[PersistedKey]。

它如何工作?

persisted 通过将每个持久化值包装在[Persisted]或[PersistedLazy]中来实现。包装器使用一个键和可选的默认值创建。向存储库发出请求以加载键的最新值,如果存在,则使用该值。每当值被修改时,存储库都会通知新的值以便可以保存(有关“已修改”的更严格定义,请参见[Persisted]或[PersistedLazy])。

因为存储库可以从构造函数和析构函数中访问,所以不能传递它,而必须是静态可达的。为此,最简单的方法是使用存储库的staticthread_local定义。

示例

下面是一个非常简单的持久化方案的示例。存储库仅保留一个值。

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

/// Store index of the selected person
#[derive(Default)]
struct Store(Cell<Option<usize>>);

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

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

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

/// Persist the selected value in the list by storing its index. This is simple
/// but relies on the list keeping the same items, in the same order, between
/// sessions.
#[derive(PersistedKey)]
#[persisted(usize)]
struct SelectedIndexKey;

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

/// A list of items, with one item selected
struct SelectList<T> {
    values: Vec<T>,
    selected_index: Persisted<Store, SelectedIndexKey>,
}

impl<T> SelectList<T> {
    fn new(values: Vec<T>) -> Self {
        Self {
            values,
            selected_index: Persisted::new(SelectedIndexKey, 0),
        }
    }

    fn selected(&self) -> &T {
        &self.values[*self.selected_index]
    }
}

let list = vec![
    Person {
        name: "Fred".into(),
        age: 17,
    },
    Person {
        name: "Susan".into(),
        age: 29,
    },
    Person {
        name: "Ulysses".into(),
        age: 40,
    },
];

let mut people = SelectList::new(list.clone());
*people.selected_index.get_mut() = 1;
println!("Selected: {}", people.selected().name);
// Selected: Susan

let people = SelectList::new(list);
// The previous value was restored
assert_eq!(*people.selected_index, 1);
println!("Selected: {}", people.selected().name);
// Selected: Susan

功能标志

persisted 支持以下 Cargo 功能

  • derive(默认):启用 derive 宏
  • serde:启用 Serialize/Deserialize 实现

依赖关系

~0.4–0.9MB
~20K SLoC