Skip to main content

datumesh_store/
lib.rs

1//! A store for [Datumesh](https://datumesh.com): function descriptors, receipts, blobs,
2//! versions of cells over transaction time, lineage, namespaces and function names, on
3//! PostgreSQL or (since 0.4.0) in one SQLite file. [`PgStore`] and [`SqliteStore`] implement
4//! [`Store`], and through it `datumesh_core`'s [`Resolver`], so `datumesh_core::verify` can
5//! recompute receipts of stored cells from either; the two behave the same (one
6//! conformance suite runs against both).
7//!
8//! The API is synchronous (the `postgres` driver and a small connection pool; `rusqlite`
9//! with SQLite compiled in, feature `sqlite`, on by default). Async callers run it on a
10//! blocking thread, e.g. `tokio::task::spawn_blocking`.
11//!
12//! [`SqliteStore::open`] takes a file path ([`SqliteStore::connect`] a `sqlite:` URL); the
13//! file is in WAL mode, every write is one `BEGIN IMMEDIATE` transaction, and the
14//! append-only rules are triggers in the file, so they hold for writers in several
15//! threads and processes on one machine. Its schema comes from [`migrate::sqlite::apply`].
16//!
17//! [`PgStore::connect`] / [`PgStore::connect_with`] take a URL and [`PoolOptions`]; TLS
18//! (rustls) is used as the URL's `sslmode` says and always verifies the server's
19//! certificate and host name, against the Mozilla roots plus those added with
20//! [`PoolOptions::tls_root_certificates_pem`]. No type of the driver or of a TLS crate is
21//! part of the API, except in [`pg_unstable`] (any connection function, the driver
22//! itself), which is outside semver until 1.0.
23//!
24//! What is stored, and how:
25//!
26//! * Descriptors are checked by the core (`FunctionDescriptor::from_json`: since 0.3.1,
27//!   spec-0.4.0's, with `signature.order` and argument `extent`) and stored in canonical
28//!   form (JCS) under their hash. Receipts are verified (`datumesh_core::verify`, SPEC 10.1
29//!   steps 1-6) against the key document stored for their signer host, so nothing
30//!   unverified enters the store, and are stored canonical under their hash. Storing the
31//!   same thing twice stores it once. A second, different valid signature over the same
32//!   payload (possible only with a randomised signer: the payload names the key, so a
33//!   rotated key gives a new hash) is refused ([`Error::Conflict`]) and the stored receipt
34//!   kept.
35//! * Blobs are stored in the database, under the SHA-256 of their content.
36//! * Versions: from transaction time `tx` on, cell `cell_id` has the value of a receipt.
37//!   Append-only and in tx order per cell, enforced by the database (triggers) as well as by
38//!   [`Store::put_version`], which also checks that the receipt is stored and is of that
39//!   cell at that tx.
40//! * Computed versions: from transaction time `tx` on, cell `cell_id` has the value a
41//!   receipt computed, as of the receipt's asof. Derived rather than facts, so they are
42//!   added in any order, keyed on (cell, tx, asof), insert-only
43//!   ([`Store::put_computed`], [`Store::computed_asof`]).
44//! * Answering as of A: a receipt answers as of A only when its `tx` and its `asof` are
45//!   both at or before A ([`Store::stored_asof`], and the [`Resolver`]'s `evaluate` of a
46//!   stored function; [`Store::version_asof`] looks at `tx` only).
47//! * Lineage: `put_receipt` records an edge to each of the receipt's `inputs`, held or not:
48//!   receipt hashes ([`Store::inputs`], [`Store::dependents`]) and, since 0.3.1, slice
49//!   entries ([`Store::slice_entries`], [`Store::slice_dependents`]);
50//!   [`Store::cell_dependents`] lifts both to cells.
51//! * Slices (0.3.1, SPEC 15.13): every stored receipt's cell is indexed by its typed
52//!   arguments, so that [`Store::slice_members`] finds the members of a slice as of A with
53//!   a range scan, in key order; [`Store::versions_between`] gives a version slice.
54//!   [`Store::slice_values`] gives the members' values without receipts (0.3.2) and
55//!   [`Store::slice_changed_after`] whether they may answer differently later.
56//!   Manifests ([`Store::put_manifest`], served by [`Resolver::manifest`]) are kept by
57//!   entry and found from each member ([`Store::member_manifests`]). A receipt citing a
58//!   slice can be stored before its manifest, and a manifest before its members.
59//! * Namespaces: a host's key document (checked as SPEC 9.2 requires), with when it was
60//!   validated. Store it before the host's receipts. Replacing it later (a key revoked or
61//!   dropped) does not touch receipts already stored: they verified when they were stored,
62//!   and putting one of them again is still idempotent.
63//! * Names: which function hash a fully qualified function name meant from a transaction
64//!   time on. Append-only, like versions. [`Store::resolve_binding`] gives the binding
65//!   answering as of A with when it began; [`Store::resolve_name`] its hash.
66//!
67//! Instants are compared as text (fixed width, `COLLATE "C"`; SQLite's default collation
68//! is the same byte order), which is exact; on PostgreSQL each is also stored as
69//! `timestamptz`, which round-trips every instant of the specification exactly. Numbers in
70//! the typed-argument index compare as exact decimals (PostgreSQL `numeric`; on SQLite a
71//! text encoding that sorts as the decimal does).
72//!
73//! Every [`Store`] method returns a `Result`: a malformed argument is [`Error::Invalid`] with
74//! the core's code, a database failure [`Error::Database`]. The [`Resolver`] methods keep the
75//! core's `Option` signatures; there a failure is logged with `tracing` (target
76//! `datumesh_store`) and answered `None`, which `verify` reports as unavailable.
77//!
78//! [`Store`] is sealed: only this crate implements it. The store is the trust boundary:
79//! everything in it was checked on the way in (every receipt verified against its host's
80//! key document), and its callers rely on that rather than checking again. A `dyn Store`
81//! is still a trait object as before.
82//!
83//! The schema comes from [`migrate::apply`] (PostgreSQL) or [`migrate::sqlite::apply`]
84//! (SQLite) (the `datumesh-store migrate` command, for either), through a store on the
85//! (possibly empty) database.
86
87#![forbid(unsafe_code)]
88#![deny(missing_docs)]
89
90use std::borrow::Cow;
91
92pub use datumesh_core::Resolver;
93use datumesh_core::{Cell, Scalar, Slice};
94
95mod error;
96pub mod migrate;
97mod pg;
98pub mod pg_unstable;
99mod pool;
100mod slices;
101mod sql;
102#[cfg(feature = "sqlite")]
103mod sqlite;
104#[cfg(feature = "sqlite")]
105mod sqlite_sql;
106mod tls;
107
108pub use error::{DatabaseError, Error, Result};
109pub use pg::PgStore;
110pub use pool::PoolOptions;
111#[cfg(feature = "sqlite")]
112pub use sqlite::{SqliteOptions, SqliteStore};
113
114/// A version of a cell: from transaction time `tx` on, the cell's value is that of the
115/// receipt `receipt_hash`, which states it as of `asof`.
116///
117/// A stored version ([`Store::put_version`]) or a computed one ([`Store::put_computed`]).
118#[non_exhaustive]
119#[derive(Clone, Debug, PartialEq, Eq, Hash)]
120pub struct Version {
121    /// The cell id.
122    pub cell_id: String,
123    /// The transaction time (an instant, SPEC 3.3).
124    pub tx: String,
125    /// The receipt stating the value.
126    pub receipt_hash: String,
127    /// The receipt's `asof` (an instant; never earlier than `tx`). Since 0.2.0.
128    pub asof: String,
129}
130
131/// A member of a slice ([`Store::slice_members`], [`Store::versions_between`]): a stored
132/// version and the bytes of its receipt (as [`receipt`](Resolver::receipt) returns them).
133/// Since 0.3.1.
134#[non_exhaustive]
135#[derive(Clone, Debug, PartialEq, Eq, Hash)]
136pub struct SliceMember {
137    /// The version answering (its cell, tx, receipt hash and asof).
138    pub version: Version,
139    /// The receipt's bytes, canonical JSON.
140    pub receipt: Vec<u8>,
141}
142
143/// A member of a slice with its value and without its receipt's bytes
144/// ([`Store::slice_values`]). Since 0.3.2.
145#[non_exhaustive]
146#[derive(Clone, Debug, PartialEq, Eq, Hash)]
147pub struct SliceValue {
148    /// The version answering (its cell, tx, receipt hash and asof).
149    pub version: Version,
150    /// The receipt's typed value.
151    pub value: Scalar,
152    /// The member's cell, with its arguments (from the store's typed-argument index; equal
153    /// to the receipt's `cell`, and `cell.id()` is `version.cell_id`).
154    pub cell: Cell,
155}
156
157/// A name binding: from transaction time `tx` on, a fully qualified function name means the
158/// function `fn_hash` ([`Store::bind_name`]). Since 0.3.0.
159#[non_exhaustive]
160#[derive(Clone, Debug, PartialEq, Eq, Hash)]
161pub struct Binding {
162    /// The function hash the name means.
163    pub fn_hash: String,
164    /// When the binding began: the transaction time from which the name means `fn_hash`
165    /// (an instant, SPEC 3.3).
166    pub tx: String,
167}
168
169/// A namespace's host and its key document.
170#[non_exhaustive]
171#[derive(Clone, Debug, PartialEq, Eq, Hash)]
172pub struct Namespace {
173    /// The host (a DNS name).
174    pub host: String,
175    /// The key document, canonical (JCS).
176    pub keydoc: Vec<u8>,
177    /// When the document was last retrieved and checked.
178    pub validated_at: String,
179    /// When the namespace was suspended, if it is. Nothing in this version sets it.
180    pub suspended_at: Option<String>,
181}
182
183/// A Datumesh store: a [`Resolver`] that can also be written to.
184///
185/// Instants are SPEC 3.3 instants (`YYYY-MM-DDTHH:MM:SS.ffffffZ`), hashes and cell ids 64
186/// lowercase hex digits, hosts DNS names and function names fully qualified. Every method,
187/// read or write, refuses anything else with the core's error code ([`Error::Invalid`]),
188/// and reports a database failure as [`Error::Database`] (or [`Error::PoolTimeout`]): a read
189/// answers `Ok(None)` / `Ok(vec![])` only when the store really holds nothing.
190///
191/// The [`Resolver`] methods keep the core's `Option` signatures: there a malformed argument
192/// or a database failure is `None` (logged with `tracing` when it is a failure), which
193/// `verify` reports as unavailable.
194///
195/// Only this crate implements `Store` (it is sealed, since 0.3.0; [`PgStore`] and, since
196/// 0.4.0, [`SqliteStore`]): the store is the trust boundary, where every receipt is verified against its host's key document before it is
197/// kept, and what a store answers is relied on as checked. An implementation elsewhere
198/// could answer anything. `Store` stays object-safe (`Arc<dyn Store + Send + Sync>`). Even a complete implementation that
199/// delegates every method to a [`PgStore`] is refused (`E0277`: the private supertrait is
200/// not implemented; `tests/sealed.rs` checks that this is the only error):
201///
202/// ```compile_fail
203/// use std::borrow::Cow;
204/// use datumesh_core::{Cell, Scalar};
205/// use datumesh_core::Slice;
206/// use datumesh_store::{Binding, Namespace, PgStore, Resolver, Result, SliceMember, SliceValue, Store, Version};
207///
208/// struct Wrapper(PgStore);
209/// impl Resolver for Wrapper {
210///     fn descriptor(&self, h: &str) -> Option<Cow<'_, [u8]>> { self.0.descriptor(h) }
211///     fn receipt(&self, h: &str) -> Option<Cow<'_, [u8]>> { self.0.receipt(h) }
212///     fn evaluate(&self, c: &Cell, a: &str) -> Option<Scalar> { self.0.evaluate(c, a) }
213///     fn manifest(&self, e: &str) -> Option<Cow<'_, [u8]>> { self.0.manifest(e) }
214/// }
215/// impl Store for Wrapper {
216///     fn put_descriptor(&self, b: &[u8]) -> Result<String> { self.0.put_descriptor(b) }
217///     fn put_receipt(&self, b: &[u8]) -> Result<String> { self.0.put_receipt(b) }
218///     fn put_blob(&self, b: &[u8]) -> Result<String> { self.0.put_blob(b) }
219///     fn blob(&self, s: &str) -> Result<Option<Cow<'_, [u8]>>> { self.0.blob(s) }
220///     fn put_version(&self, c: &str, t: &str, r: &str) -> Result<()> { self.0.put_version(c, t, r) }
221///     fn version_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.version_asof(c, a) }
222///     fn versions(&self, c: &str, f: &str, t: &str) -> Result<Vec<Version>> { self.0.versions(c, f, t) }
223///     fn latest(&self, c: &str) -> Result<Option<Version>> { self.0.latest(c) }
224///     fn dependents(&self, r: &str) -> Result<Vec<String>> { self.0.dependents(r) }
225///     fn inputs(&self, r: &str) -> Result<Vec<String>> { self.0.inputs(r) }
226///     fn put_namespace(&self, h: &str, k: &[u8], v: &str) -> Result<()> { self.0.put_namespace(h, k, v) }
227///     fn namespace(&self, h: &str) -> Result<Option<Namespace>> { self.0.namespace(h) }
228///     fn bind_name(&self, n: &str, f: &str, t: &str) -> Result<()> { self.0.bind_name(n, f, t) }
229///     fn resolve_name(&self, n: &str, a: &str) -> Result<Option<String>> { self.0.resolve_name(n, a) }
230///     fn resolve_binding(&self, n: &str, a: &str) -> Result<Option<Binding>> { self.0.resolve_binding(n, a) }
231///     fn put_computed(&self, c: &str, t: &str, r: &str) -> Result<()> { self.0.put_computed(c, t, r) }
232///     fn computed_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.computed_asof(c, a) }
233///     fn stored_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.stored_asof(c, a) }
234///     fn cell_dependents(&self, c: &str) -> Result<Vec<String>> { self.0.cell_dependents(c) }
235///     fn put_manifest(&self, b: &[u8]) -> Result<String> { self.0.put_manifest(b) }
236///     fn member_manifests(&self, r: &str) -> Result<Vec<String>> { self.0.member_manifests(r) }
237///     fn slice_entries(&self, r: &str) -> Result<Vec<String>> { self.0.slice_entries(r) }
238///     fn slice_dependents(&self, e: &str) -> Result<Vec<String>> { self.0.slice_dependents(e) }
239///     fn slice_members(&self, s: &Slice, a: &str) -> Result<Vec<SliceMember>> { self.0.slice_members(s, a) }
240///     fn versions_between(&self, c: &str, f: &str, t: &str, a: &str) -> Result<Vec<SliceMember>> { self.0.versions_between(c, f, t, a) }
241///     fn slice_values(&self, s: &Slice, a: &str) -> Result<Vec<SliceValue>> { self.0.slice_values(s, a) }
242///     fn slice_changed_after(&self, s: &Slice, a: &str) -> Result<bool> { self.0.slice_changed_after(s, a) }
243/// }
244/// ```
245pub trait Store: Resolver + sealed::Sealed {
246    /// Stores a descriptor (checked and canonicalised by the core); returns its function
247    /// hash. Idempotent.
248    fn put_descriptor(&self, bytes: &[u8]) -> Result<String>;
249    /// Stores a receipt that verifies (SPEC 10.1 steps 1-6) against the key document stored
250    /// for its signer host with [`put_namespace`](Store::put_namespace), in canonical form,
251    /// with an edge to each of its inputs; returns its hash. An input that is a slice entry
252    /// (`slice:<slice id>:<members hash>`, since 0.3.1) is recorded as such
253    /// ([`slice_entries`](Store::slice_entries)); its manifest need not be stored, before or
254    /// after (it is needed only to recompute, SPEC 10.1 step 7.5). The receipt's cell is
255    /// indexed by its typed arguments ([`slice_members`](Store::slice_members)). A receipt that does not verify
256    /// is refused with `verify`'s code (no key document for the host: `E_KEY_UNAVAILABLE`).
257    /// Idempotent: bytes whose canonical form is the stored copy return its hash without
258    /// checking the signature again (it verified when stored), even if the key has since
259    /// been revoked. Other bytes with a stored hash are verified first, then refused as
260    /// [`Error::Conflict`].
261    fn put_receipt(&self, bytes: &[u8]) -> Result<String>;
262    /// Stores blob content; returns its SHA-256 (lowercase hex). Idempotent.
263    fn put_blob(&self, bytes: &[u8]) -> Result<String>;
264    /// Blob content by SHA-256.
265    fn blob(&self, sha256: &str) -> Result<Option<Cow<'_, [u8]>>>;
266    /// Appends a version: from `tx` on, `cell_id` has the value of receipt `receipt_hash`,
267    /// which must be stored, of that cell and at that tx. `tx` must be later than the cell's
268    /// latest version ([`Error::NotLater`]).
269    fn put_version(&self, cell_id: &str, tx: &str, receipt_hash: &str) -> Result<()>;
270    /// The cell's latest version with `tx <= asof`.
271    fn version_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>;
272    /// The cell's versions with `from <= tx <= to`, in tx order.
273    fn versions(&self, cell_id: &str, from: &str, to: &str) -> Result<Vec<Version>>;
274    /// The cell's latest version.
275    fn latest(&self, cell_id: &str) -> Result<Option<Version>>;
276    /// The stored receipts that list `receipt_hash` among their inputs, by hash. Only as
277    /// an input of its own: a receipt read as a member of a slice is found through its
278    /// manifests ([`member_manifests`](Store::member_manifests), then
279    /// [`slice_dependents`](Store::slice_dependents)).
280    fn dependents(&self, receipt_hash: &str) -> Result<Vec<String>>;
281    /// The inputs of a stored receipt that are receipt hashes (whether or not they are
282    /// stored). Its slice entries are [`slice_entries`](Store::slice_entries).
283    fn inputs(&self, receipt_hash: &str) -> Result<Vec<String>>;
284    /// Records a host's key document, checked as a 200 response for that host would be
285    /// (SPEC 9.2, 9.3), validated at `validated_at`. Re-validation replaces the document; a
286    /// `validated_at` earlier than the recorded one is [`Error::NotLater`]. Receipts already
287    /// stored are not re-checked: they verified when they were stored (and putting one again
288    /// stays idempotent).
289    fn put_namespace(&self, host: &str, keydoc_bytes: &[u8], validated_at: &str) -> Result<()>;
290    /// A host's recorded key document.
291    fn namespace(&self, host: &str) -> Result<Option<Namespace>>;
292    /// Appends a binding: from `tx` on, the fully qualified function name `fn_name` means
293    /// `fn_hash`, whose descriptor must be stored. `tx` must be later than the name's latest
294    /// binding ([`Error::NotLater`]).
295    fn bind_name(&self, fn_name: &str, fn_hash: &str, tx: &str) -> Result<()>;
296    /// The function hash `fn_name` meant as of `asof`: the hash of
297    /// [`resolve_binding`](Store::resolve_binding)'s binding.
298    fn resolve_name(&self, fn_name: &str, asof: &str) -> Result<Option<String>>;
299    /// The binding of `fn_name` that answers as of `asof`: the one with the latest `tx <=
300    /// asof`, with its function hash and its `tx`, when it began; `None` before the first.
301    /// A name bound again to a hash it meant before (even the hash of the binding before
302    /// it) begins again: the later binding's `tx`. Since 0.3.0.
303    fn resolve_binding(&self, fn_name: &str, asof: &str) -> Result<Option<Binding>>;
304
305    /// Records that `receipt_hash` (stored, a receipt of `cell_id` at `tx`) is a computed
306    /// version of the cell. Insert-only, in any order (an older version may be added after a
307    /// newer one): `tx` need not be later than anything. The version's asof is the
308    /// receipt's. Idempotent for the same (cell_id, tx, asof, receipt_hash); another receipt
309    /// for an existing (cell_id, tx, asof) is [`Error::Conflict`] (its `hash` is the receipt
310    /// refused) and the stored one is kept. The receipt is checked as for
311    /// [`put_version`](Store::put_version): [`Error::NotFound`] when it is not stored,
312    /// [`Error::Mismatch`] when it is of another cell or at another tx. Since 0.2.0.
313    fn put_computed(&self, cell_id: &str, tx: &str, receipt_hash: &str) -> Result<()>;
314    /// The computed version that answers as of `asof`: the one with the greatest asof <=
315    /// `asof` (between equal asof, the greatest tx), or `None`. Since 0.2.0.
316    fn computed_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>;
317    /// The stored version that answers as of `asof`: the latest version (by tx) with `tx <=
318    /// asof` whose receipt's asof is also `<= asof`, or `None`. A version whose receipt is
319    /// late-signed (asof later than tx) answers only from its asof on; until then the
320    /// version before it answers. ([`version_asof`](Store::version_asof) keeps its tx-only
321    /// meaning.) Since 0.2.0.
322    fn stored_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>;
323    /// The cells that read `cell_id`: the cell ids of the stored receipts that list, among
324    /// their inputs, any stored receipt of `cell_id` (lineage: edges joined to receipts),
325    /// or (since 0.3.1) a slice entry whose stored manifest lists one as a member.
326    /// Ascending, each once. Since 0.2.0.
327    fn cell_dependents(&self, cell_id: &str) -> Result<Vec<String>>;
328
329    /// Stores a manifest (SPEC 15.13), `{"members": [...], "slice": {...}}`: parsed strictly
330    /// and checked by the core (`Manifest::from_json`: structure, members, their order and
331    /// limit, the slice object), kept in canonical form under its entry
332    /// `slice:<slice id>:<members hash>`, which it returns, and recorded for each member
333    /// ([`member_manifests`](Store::member_manifests)). The members need not be stored.
334    /// Idempotent; insert-only (the entry is a hash of the content, so a stored entry
335    /// always has these bytes). Served by [`manifest`](Resolver::manifest). Since 0.3.1.
336    fn put_manifest(&self, bytes: &[u8]) -> Result<String>;
337    /// The entries of the stored manifests that list `receipt_hash` among their members,
338    /// ascending: from a member, the slices it was read in (then
339    /// [`slice_dependents`](Store::slice_dependents)). Since 0.3.1.
340    fn member_manifests(&self, receipt_hash: &str) -> Result<Vec<String>>;
341    /// The slice entries among the inputs of a stored receipt, ascending. Since 0.3.1.
342    fn slice_entries(&self, receipt_hash: &str) -> Result<Vec<String>>;
343    /// The stored receipts whose inputs list the slice entry `entry`, by hash, ascending.
344    /// An entry is `slice:` and two 64-digit hashes (`E_CANON_HEX` otherwise). Since 0.3.1.
345    fn slice_dependents(&self, entry: &str) -> Result<Vec<String>>;
346    /// The members of `slice` as of `asof` (SPEC 15.13), with the stored version of each
347    /// that answers as of `asof` and its receipt's bytes.
348    ///
349    /// For a slice of cells: the cells of the slice's function (its `fn_hash`, `ns` and
350    /// `fn`, with the same argument names) whose bound arguments are the same typed scalar,
351    /// whose ranged arguments are of the range's type and within it (`lo <= v <= hi`,
352    /// inclusive, in the type's order: numbers as exact decimals, dates and instants
353    /// chronologically, strings by code point; `lo` after `hi` is empty), any value for an
354    /// open argument, and that have a stored version answering as of `asof`: as
355    /// [`stored_asof`](Store::stored_asof), the latest version with `tx <= asof` whose
356    /// receipt's `asof <= asof` (so a late-signed version is not a member's answer before
357    /// its asof, and a correction replaces a member's version from its asof on). Computed
358    /// versions are not members. In key order: by the open and ranged arguments in
359    /// ascending name order, each in its type's order (`false` before `true`; blobs as
360    /// text); the cell id last, for two cells whose key arguments are of different types.
361    ///
362    /// For a version slice `{"cell", "from", "to"}`: [`versions_between`](Store::versions_between)
363    /// of its cell. Empty when nothing matches. Since 0.3.1.
364    fn slice_members(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceMember>>;
365    /// The stored versions of `cell_id` with `from <= tx <= to` that answer as of `asof`
366    /// (`tx <= asof` and the receipt's `asof <= asof`), ascending by tx, each with its
367    /// receipt's bytes: SPEC 15.13's version slice. Empty when `from` is after `to`. Since
368    /// 0.3.1.
369    fn versions_between(&self, cell_id: &str, from: &str, to: &str, asof: &str) -> Result<Vec<SliceMember>>;
370    /// The members [`slice_members`](Store::slice_members) gives, in its order and by its
371    /// answering rule, each as its version, its receipt's typed value and its cell (with its
372    /// arguments), without the receipt's bytes (the value is a stored column of the receipt
373    /// and the cell comes from the typed-argument index, neither parsed per call).
374    /// Since 0.3.2.
375    fn slice_values(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceValue>>;
376    /// Whether the members of `slice`, or their versions, may answer differently as of some
377    /// time after `asof`: whether a cell matching the slice has a stored version whose
378    /// receipt's `asof` is after `asof` (its `tx` is never later than that), for a version
379    /// slice one with `tx` in `[from, to]`. `false` means [`slice_members`](Store::slice_members)
380    /// (and `slice_values`) give the same answer as of every time from `asof` on, until a
381    /// version is stored with an asof after it; `true` may be conservative (a late-signed
382    /// version superseded before its asof never answers). Index scans only, whatever the
383    /// slice's size: two bounded probes (at most 10,001 entries each) choose whether to walk
384    /// the function's receipts with an asof after `asof` or the slice's candidate cells,
385    /// whichever is fewer, and one query walks it, stopping at the first match. Since 0.3.2.
386    fn slice_changed_after(&self, slice: &Slice, asof: &str) -> Result<bool>;
387
388    /// [`computed_asof`](Store::computed_asof) and the bytes of the version's receipt (as
389    /// [`receipt`](Resolver::receipt) returns them), which is what a caller reads next.
390    /// The default asks for the two in turn (a receipt that cannot be read then is
391    /// [`Error::NotFound`]); [`PgStore`] and [`SqliteStore`] answer both with one query.
392    /// Since 0.2.0.
393    fn computed_asof_with_receipt(&self, cell_id: &str, asof: &str) -> Result<Option<(Version, Cow<'_, [u8]>)>> {
394        match self.computed_asof(cell_id, asof)? {
395            Some(v) => with_receipt(self, v).map(Some),
396            None => Ok(None),
397        }
398    }
399    /// [`stored_asof`](Store::stored_asof) and the bytes of the version's receipt, as
400    /// [`computed_asof_with_receipt`](Store::computed_asof_with_receipt) does. Since 0.2.0.
401    fn stored_asof_with_receipt(&self, cell_id: &str, asof: &str) -> Result<Option<(Version, Cow<'_, [u8]>)>> {
402        match self.stored_asof(cell_id, asof)? {
403            Some(v) => with_receipt(self, v).map(Some),
404            None => Ok(None),
405        }
406    }
407}
408
409/// The seal of [`Store`]: a public trait in a private module, so no other crate can name it,
410/// and so none can implement `Store`.
411mod sealed {
412    pub trait Sealed {}
413    impl Sealed for crate::PgStore {}
414    #[cfg(feature = "sqlite")]
415    impl Sealed for crate::SqliteStore {}
416}
417
418/// A version and its receipt's bytes, for the default `*_with_receipt` methods.
419fn with_receipt<S: Store + ?Sized>(store: &S, v: Version) -> Result<(Version, Cow<'_, [u8]>)> {
420    match store.receipt(&v.receipt_hash) {
421        Some(bytes) => Ok((v, bytes)),
422        None => Err(Error::NotFound { what: "receipt", key: v.receipt_hash }),
423    }
424}