1#![doc = include_str!("../README.md")]
2#![no_std]
3
4pub mod path;
5pub use path::Path;
6
7#[cfg(feature = "tokio")]
8pub mod async_query;
9#[cfg(feature = "tokio")]
10pub use async_query::{requester, Requester};
11
12extern crate alloc;
13use alloc::{
14 boxed::Box,
15 collections::{btree_map::Entry, BTreeMap},
16};
17use core::{clone::Clone, ops::Bound};
18use edfsm::{Change, Drain, Fsm, Init, Input, Terminating};
19use serde::{Deserialize, Serialize};
20
21pub type Event<M> = <M as Fsm>::E;
23
24pub type Command<M> = <M as Fsm>::C;
26
27pub type In<M> = Input<<M as Fsm>::C, <M as Fsm>::E>;
29
30pub type Out<M> = <<M as Fsm>::SE as Drain>::Item;
32
33pub type Effect<M> = <M as Fsm>::SE;
35
36pub type State<M> = <M as Fsm>::S;
38
39pub enum Query<V, E> {
51 Get(Path, RespondOne<V, ()>),
53
54 GetTree(Path, RespondMany<V, ()>),
57
58 GetRange((Bound<Path>, Bound<Path>), RespondMany<V, ()>),
60
61 GetAll(RespondMany<V, ()>),
63
64 Upsert(Path, RespondOne<V, E>),
66
67 Insert(RespondMany<V, Keyed<E>>),
69}
70
71pub type RespondMany<V, E> = Box<dyn FnOnce(&mut dyn Iterator<Item = (&Path, &V)>) -> E + Send>;
73
74pub type RespondOne<V, E> = Box<dyn FnOnce(Option<&V>) -> E + Send>;
76
77pub struct KvStore<M>(BTreeMap<Path, State<M>>)
86where
87 M: Fsm;
88
89impl<M> Fsm for KvStore<M>
90where
91 M: Fsm + 'static,
92 State<M>: Default,
93 Event<M>: Terminating,
94 Effect<M>: Drain,
95{
96 type S = Self;
97 type C = Query<State<M>, Event<M>>;
98 type E = Keyed<Event<M>>;
99 type SE = Keyed<Effect<M>>;
100
101 fn for_command(store: &Self::S, command: Self::C, _se: &mut Self::SE) -> Option<Self::E> {
102 use Bound::*;
103 use Query::*;
104 match command {
105 Get(path, respond) => {
106 respond(store.0.get(&path));
107 None
108 }
109 GetTree(path, respond) => {
110 respond(
111 &mut (store
112 .0
113 .range((Included(&path), Unbounded))
114 .take_while(|(p, _)| p.len() > path.len() || *p == &path)),
115 );
116 None
117 }
118 GetRange(bounds, respond) => {
119 respond(&mut store.0.range(bounds));
120 None
121 }
122 GetAll(respond) => {
123 respond(&mut store.0.iter());
124 None
125 }
126 Upsert(path, respond) => {
127 let e = respond(store.0.get(&path));
128 Some(Keyed { key: path, item: e })
129 }
130 Insert(respond) => {
131 let e = respond(&mut store.0.iter());
132 Some(e)
133 }
134 }
135 }
136
137 fn on_event(r: &mut Self::S, e: &Self::E) -> Option<Change> {
138 use Entry::*;
139 match (r.0.entry(e.key.clone()), e.item.terminating()) {
140 (Occupied(entry), false) => {
141 let s = entry.into_mut();
142 M::on_event(s, &e.item)
143 }
144 (Vacant(entry), false) => {
145 let s = entry.insert(Default::default());
146 M::on_event(s, &e.item)
147 }
148 (Occupied(entry), true) => {
149 entry.remove();
150 Some(Change::Transitioned)
151 }
152 (Vacant(_), true) => None,
153 }
154 }
155
156 fn on_change(r: &Self::S, e: &Self::E, se: &mut Self::SE, change: Change) {
157 if let Some(s) = r.0.get(&e.key) {
158 se.key = e.key.clone();
159 M::on_change(s, &e.item, &mut se.item, change);
160 }
161 }
162}
163
164#[derive(Clone, Debug, Serialize, Deserialize)]
168pub struct Keyed<A> {
169 pub key: Path,
170 pub item: A,
171}
172
173impl<M> Default for KvStore<M>
174where
175 M: Fsm,
176{
177 fn default() -> Self {
178 Self(BTreeMap::new())
179 }
180}
181
182impl<SE> Drain for Keyed<SE>
183where
184 SE: Drain,
185{
186 type Item = Keyed<SE::Item>;
187
188 fn drain_all(&mut self) -> impl Iterator<Item = Self::Item> + Send {
189 self.item.drain_all().map(|item| Keyed {
190 key: self.key.clone(),
191 item,
192 })
193 }
194}
195
196impl<A> Terminating for Keyed<A> {
197 fn terminating(&self) -> bool {
198 false
199 }
200}
201
202impl<S, SE> Init<S> for Keyed<SE> {
203 fn init(&mut self, _state: &S) {}
204}
205
206impl<SE> Default for Keyed<SE>
207where
208 SE: Default,
209{
210 fn default() -> Self {
211 Self {
212 key: Default::default(),
213 item: Default::default(),
214 }
215 }
216}