Быстрый старт
Кратчайший путь от пустого места до работающего store. На каждом шаге — ссылка на раздел, где этот шаг разобран как следует.
Всё, что импортируется ниже, лежит в прелюдии, и обычная программа берёт её целиком:
use amethystate::prelude::*;В ней есть всё, что нужно, чтобы объявить, открыть, прочитать и записать, — в
том числе StoreExt и StoreBackend. Это трейты, и без них у store как будто
нет ни get, ни save_now. В примерах ниже импорты выписаны поимённо, чтобы
было видно, откуда что берётся.
Объявите состояние
Заголовок раздела «Объявите состояние»Один атрибут — и поля структуры живут в store и будят подписчиков. prefix
задаёт, где они лежат.
use amethystate::amethystate;
#[amethystate(prefix = "network")]pub struct NetworkState { #[amestate(default = "127.0.0.1".to_string())] pub host: String,
#[amestate(default = 8080u16)] pub port: u16,}Значения по умолчанию, вложенные структуры, volatile-поля, политики чтения, правила для значений и serde — в разделе Состояние.
Создайте store
Заголовок раздела «Создайте store»let store = StoreBuilder::new(settings) .disk(|d| d.debounce(Duration::from_millis(500))) .build()?;
let state = NetworkState::new_with(&store);new_with принимает параметром Store — тот, что вы держите сами. Как открыть
один на весь процесс, дать платформе выбрать место для файла и что вернёт
close, если последний сброс не удался:
Открытие store.
Задержки, повторные попытки и то, чего store не примет: Настройка store. В какой файл пишет движок: Установка.
Читайте, пишите, подписывайтесь
Заголовок раздела «Читайте, пишите, подписывайтесь»println!("{}", state.host().get());
let _sub = state.port().subscribe(|port| { println!("port changed to {port}");});
state.port().set(9090);Запись доходит до памяти сразу, до диска — с задержкой. Как звать колбэки в своём потоке, отсеивать собственные записи и сколько стоит подписка: Подписки.
Кому нужна запись сейчас, а не «когда-нибудь потом»: Durability.
Ключи, которые появляются в рантайме
Заголовок раздела «Ключи, которые появляются в рантайме»Карта кладёт каждую запись по своему пути — добавлять и слушать можно по одной.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]pub struct AlertThresholds { pub warning: u64, pub critical: u64,}
#[amethystate(prefix = "sys")]pub struct SystemSettings { #[amestate(default = { "cpu": AlertThresholds { warning: 70, critical: 90 }, "mem": AlertThresholds { warning: 80, critical: 95 } })] pub limits: ReactiveMap<String, AlertThresholds>,}state.limits().insert( "gpu".to_string(), &AlertThresholds { warning: 60, critical: 85, },)?;
let cpu = state.limits().get("cpu");
for (key, value) in state.limits().entries() { println!("{key}: {value:?}");}
let _sub = state.limits().subscribe_any(|change| { println!("{change:?}");});entries() отдаёт записи в порядке store — то есть по именам, которые ключи
одалживают. Нестроковый ключ идёт через Id и упорядочен по написанию, которое
Id держит, поэтому Id<u16> приходит как 10, 100, 9.
Пути, которые складываются уже в рантайме, обходятся без структуры: их держит Kv. А когда такой путь один и за его значением надо следить, ReactiveCell даёт по нему то же, что поле даёт по объявленному, — чтение, запись и подписку.
Когда структура меняется
Заголовок раздела «Когда структура меняется»Поднимите version и объявите шаги между версиями — тогда библиотека перенесёт
данные, записанные старой сборкой. Поле переименовали или сменили ему тип, а
версию не подняли — это дрейф: о нём скажут, и запуск продолжится.
Открывайте store через migrate всегда, когда в бинарнике есть #[migrate]:
build не выполняет ни одного шага.
Режим Persistent-only
Заголовок раздела «Режим Persistent-only»Для фреймворков с явным циклом отрисовки/обновления — egui, iced, ratatui —
mode = "persistent" оставляет поля обычными: сохраняются вручную.
#[amethystate(prefix = "kept", mode = "persistent")]pub struct KeptSettings { #[amestate(default = "127.0.0.1".to_string())] pub host: String,
#[amestate(default = 8080u16)] pub port: u16,}let mut state = KeptSettings::load_with(&store);
state.port = 9090;state.save()?;
state.mutate(|d| { d.host = "0.0.0.0".to_string(); d.port = 443;})?;save_lazy и mutate_lazy делают то же самое, но на диск сбрасывает
дебаунсер.
Что ещё есть
Заголовок раздела «Что ещё есть»- Правила — функция на поле, которая поправляет каждое значение, которое поле берёт: Правила.
- Трассировка — структурированные события: каждая запись помечена структурой, которая её сделала: Наблюдаемость.
- guinea — таймер, период которого следует за сохранённой настройкой: guinea.