git-ents.gitmain
⌘K
foforge
edit.rs95 lines · 3.0 KB · rusthistorycomment on this file
1//! The vocabulary of a [`crate::RefStore::transaction`] call: what a
2//! [`RefEdit`] expects a ref to hold, what a batch of them can do
3//! atomically, and how the store reports which one failed.
4
5use gix::refs::FullName;
6use gix_hash::ObjectId;
7
8/// The compare-and-swap precondition a [`RefEdit`] requires of a ref's
9/// current value before the edit is allowed to apply.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum Expected {
12 /// No requirement: set unconditionally.
13 Any,
14 /// The ref must not currently exist.
15 MustNotExist,
16 /// The ref must currently exist and equal the given object id.
17 MustExistAndMatch(ObjectId),
18}
19
20/// One ref's half of a [`crate::RefStore::transaction`] batch: what `name`
21/// is expected to hold, and what it should become. `new: None` deletes the
22/// ref.
23///
24/// # Examples
25///
26/// ```
27/// use gix_hash::ObjectId;
28/// use gix_ref_store::{Expected, RefEdit};
29///
30/// let oid = ObjectId::null(gix_hash::Kind::Sha1);
31/// let edit = RefEdit {
32/// name: "refs/meta/config".try_into().expect("valid refname"),
33/// expected: Expected::MustNotExist,
34/// new: Some(oid),
35/// };
36/// assert_eq!(edit.new, Some(oid));
37/// ```
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct RefEdit {
40 /// The ref this edit applies to.
41 pub name: FullName,
42 /// The compare-and-swap precondition checked against `name`'s current
43 /// value before the edit applies.
44 pub expected: Expected,
45 /// The value to set `name` to, or `None` to delete it.
46 pub new: Option<ObjectId>,
47}
48
49/// The result of a [`crate::RefStore::transaction`] call that itself
50/// completed (returned `Ok`): either every edit applied, or none did.
51///
52/// A `Rejected` outcome is not an [`crate::Error`] — a stale
53/// compare-and-swap precondition is an expected, checkable result, not a
54/// backend fault.
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum TxOutcome {
57 /// Every edit in the batch applied atomically.
58 Applied,
59 /// The transaction did not apply: `name`'s current value did not match
60 /// its edit's [`Expected`] precondition. No edit in the batch took
61 /// effect — compare-and-swap is all-or-nothing, per the trait's
62 /// contract.
63 Rejected {
64 /// The first ref whose precondition failed.
65 name: FullName,
66 },
67}
68
69/// An iterator over `(name, tip)` pairs from a
70/// [`crate::RefStoreRead::iter_prefix`] query, wrapping whatever iterator
71/// the backend produces so the trait itself stays object-safe.
72pub struct RefIter(Box<dyn Iterator<Item = crate::Result<(FullName, ObjectId)>> + Send>);
73
74impl RefIter {
75 /// Wrap `iter` as a [`RefIter`].
76 pub fn new(
77 iter: impl Iterator<Item = crate::Result<(FullName, ObjectId)>> + Send + 'static,
78 ) -> Self {
79 Self(Box::new(iter))
80 }
81}
82
83impl Iterator for RefIter {
84 type Item = crate::Result<(FullName, ObjectId)>;
85
86 fn next(&mut self) -> Option<Self::Item> {
87 self.0.next()
88 }
89}
90
91impl std::fmt::Debug for RefIter {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.write_str("RefIter(..)")
94 }
95}