somatize_core/keeper.rs
1//! Who hashes and who keeps. The hole.
2//!
3//! The same shape as the rest, and the reason is the same: **the core provides
4//! the hole; whoever knows what goes in it is a library.** Here it is doubly
5//! true — hashing is `sha256` and keeping is a directory or a bucket, and the
6//! core has no dependencies at all.
7//!
8//! | hole | who fills it | what they know that the core does not |
9//! |---|---|---|
10//! | [`Node`](crate::Node) | the user | what a node does |
11//! | [`Transport`](crate::Transport) | a library | what a wire is |
12//! | [`Codec`](crate::Codec) | a library | how to write down what lives in one process |
13//! | [`Watcher`](crate::Watcher) | whoever executes | what to do with a fact |
14//! | `Keeper` | a library | what a hash is, and where bytes live |
15
16use crate::{Key, Value};
17use std::fmt;
18
19/// Hashes recipes and keeps what they name.
20pub trait Keeper: Send + Sync {
21 /// The key of a value **by its content**, which only a root needs: from
22 /// there down, keys come from keys. `None` if the value cannot leave this
23 /// process, which is not a failure — nothing below it is cached either.
24 fn key_of(&self, value: &Value) -> Option<Key>;
25
26 /// One key out of the ingredients of a recipe, in the order given. **The
27 /// parts have to stay apart**: run together, `["ab", "c"]` and
28 /// `["a", "bc"]` would name the same thing.
29 fn combine(&self, parts: &[&str]) -> Key;
30
31 /// What is kept under each of these, in the order they were asked. In batch
32 /// form from the first day: against a remote store, one question per item is
33 /// one round trip per item.
34 fn recall(&self, keys: &[&Key]) -> Result<Vec<Option<Kept>>, KeeperError>;
35
36 /// Whether each of these is kept, **without reading any of it**.
37 ///
38 /// A key is knowable before anything runs, so the engine can ask which
39 /// answers it already has and then not execute what only fed one of them.
40 /// The default is honest and expensive — it reads them; whoever can answer
41 /// by name alone should say so, or asking early costs what it saves.
42 fn present(&self, keys: &[&Key]) -> Result<Vec<bool>, KeeperError> {
43 Ok(self
44 .recall(keys)?
45 .into_iter()
46 .map(|kept| kept.is_some())
47 .collect())
48 }
49
50 /// Keeps this, with what should be remembered beside it — the fingerprint
51 /// of the code that produced it, above all, which is **not** in the key and
52 /// is what a hit gets compared against.
53 fn keep(&self, key: &Key, value: &Value, meta: &[(&str, &str)]) -> Result<(), KeeperError>;
54}
55
56/// Something that was kept, on the way back: the value, and what was said
57/// beside it. The metadata comes back because the fingerprint of the code is
58/// not in the key — it is written next to the value and compared on a hit.
59#[derive(Debug, Clone, PartialEq)]
60pub struct Kept {
61 /// What was kept.
62 pub value: Value,
63 /// What was said beside it, in the order it was said.
64 pub meta: Vec<(String, String)>,
65}
66
67/// Why something could not be kept, or found.
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct KeeperError(String);
70
71impl KeeperError {
72 /// A failure described by a message.
73 pub fn new(message: impl Into<String>) -> Self {
74 Self(message.into())
75 }
76
77 /// The message.
78 pub fn message(&self) -> &str {
79 &self.0
80 }
81}
82
83impl fmt::Display for KeeperError {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.write_str(&self.0)
86 }
87}
88
89impl std::error::Error for KeeperError {}