Skip to main content

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 {}