git-ents.gitmain
⌘K
foforge
store.rs50 lines · 2.1 KB · rusthistorycomment on this file
1//! The write (CAS) half of the `RefStore` seam.
2
3use crate::{RefEdit, RefStoreRead, Result, TxOutcome};
4
5/// The unit of correctness for repository state: a store of named refs,
6/// each pointing at an object id, updated only through atomic
7/// compare-and-swap transactions.
8///
9/// `RefStore` extends [`RefStoreRead`] rather than duplicating its
10/// methods, so any code already written against the read half keeps
11/// working unchanged when handed a full store. `arch.refstore-read-cas-split`
12/// is about restricting what the *gate* is handed, not about the store
13/// implementation's own shape: one type legitimately implements both
14/// halves, as [`crate::LooseRefStore`] does.
15///
16/// # Contract
17///
18/// Multi-ref compare-and-swap is contractual, not a capability query. A
19/// backend that cannot apply an arbitrary batch of [`RefEdit`]s atomically
20/// — every precondition checked against one consistent view, and either
21/// every edit applies or none do — does not satisfy this trait, full stop.
22///
23/// # Examples
24///
25/// ```
26/// use gix_hash::ObjectId;
27/// use gix_ref_store::{Expected, LooseRefStore, RefEdit, RefStore, RefStoreRead, TxOutcome};
28///
29/// # fn run(dir: &std::path::Path, oid: ObjectId) -> gix_ref_store::Result<()> {
30/// let store = LooseRefStore::open(dir)?;
31/// let name: gix::refs::FullName = "refs/meta/config".try_into().expect("valid refname");
32/// let outcome = store.transaction(&[RefEdit {
33/// name: name.clone(),
34/// expected: Expected::MustNotExist,
35/// new: Some(oid),
36/// }])?;
37/// assert_eq!(outcome, TxOutcome::Applied);
38/// assert_eq!(store.get(name.as_ref())?, Some(oid));
39/// # Ok(())
40/// # }
41/// ```
42// @relation(arch.refstore-read-cas-split, scope=file)
43pub trait RefStore: RefStoreRead {
44 /// Apply `edits` as one atomic compare-and-swap transaction: every
45 /// edit's [`crate::Expected`] precondition is checked against the same
46 /// consistent view of the store, and either every edit applies or none
47 /// do. See the trait's contract above — this is not optional behavior
48 /// a backend may approximate.
49 fn transaction(&self, edits: &[RefEdit]) -> Result<TxOutcome>;
50}