mirror of
https://seed.radicle.dev/rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt.git
synced 2026-11-03 02:10:32 +08:00
This provides a port of the librad::git::storage[0] API, with a focus on being more generic and decomposing writing and reading operations. It also takes heavy inspiration from link_replication::io::refdb[1] for its implementation of the transactional writes. [0]: https://github.com/radicle-dev/radicle-link/blob/master/librad/src/git/storage.rs [1]: https://github.com/radicle-dev/radicle-link/blob/master/link-replication/src/io/refdb.rs Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
133 lines
4.4 KiB
Rust
133 lines
4.4 KiB
Rust
// Copyright © 2022 The Radicle Link Contributors
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
//! The [`Edit`] and [`Remove`] enums provide a mechanism for protecting updates
|
|
//! during concurrent writes to the refdb. The value is constructed with the
|
|
//! policy, sometimes providing the expected previous value of the [`Oid`]
|
|
//! target. If this policy is not satisfied then the update should be rejected.
|
|
|
|
use git_ext::Oid;
|
|
|
|
use thiserror::Error;
|
|
|
|
/// The expectation of the reference's state.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
pub enum Edit {
|
|
/// No requirements are made towards the current value, and the new value is
|
|
/// set unconditionally.
|
|
Any,
|
|
/// The reference must exist and may have any value.
|
|
MustExist,
|
|
/// Create the ref only, hence the reference must not exist.
|
|
MustNotExist,
|
|
/// The ref _must_ exist and have the given value.
|
|
MustExistAndMatch(Oid),
|
|
/// The ref _may_ exist and have the given value, or may not exist at all.
|
|
MayExistAndMatch(Oid),
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Error)]
|
|
pub enum EditError {
|
|
#[error("the reference does not exist when it was expected to exist")]
|
|
DoesNotExist,
|
|
#[error("the reference does exist when it was expected not to exist")]
|
|
DoesExist,
|
|
#[error("the reference does not match - given: '{given}' expected: '{expected}'")]
|
|
DoesNotMatch { given: Oid, expected: Oid },
|
|
}
|
|
|
|
impl Edit {
|
|
/// Guard against the `given` value using this [`Edit`].
|
|
///
|
|
/// The function will return [`Err`] if the `given` value does not pass the
|
|
/// policy the policy of the [`Edit`].
|
|
///
|
|
/// The `given` value is presumed non-existing if set to `None`, otherwise
|
|
/// it is presumed to be existing.
|
|
pub fn guard(&self, given: Option<Oid>) -> Result<(), EditError> {
|
|
use EditError::*;
|
|
|
|
match self {
|
|
Self::Any => Ok(()),
|
|
Self::MustExist => {
|
|
if given.is_none() {
|
|
Err(DoesNotExist)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
},
|
|
Self::MustNotExist => {
|
|
if given.is_some() {
|
|
Err(DoesExist)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
},
|
|
Self::MustExistAndMatch(expected) => match given {
|
|
Some(given) if &given == expected => Ok(()),
|
|
Some(given) => Err(DoesNotMatch {
|
|
given,
|
|
expected: *expected,
|
|
}),
|
|
None => Err(DoesNotExist),
|
|
},
|
|
Self::MayExistAndMatch(expected) => match given {
|
|
Some(given) if &given == expected => Ok(()),
|
|
Some(given) => Err(DoesNotMatch {
|
|
given,
|
|
expected: *expected,
|
|
}),
|
|
None => Ok(()),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The expectation of the existing reference's state.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
pub enum Remove {
|
|
/// The reference must exist and may have any value.
|
|
MustExist,
|
|
/// The ref _must_ exist and have the given value.
|
|
MustExistAndMatch(Oid),
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Error)]
|
|
pub enum RemoveError {
|
|
#[error("the reference does not exist when it was expected to exist")]
|
|
DoesNotExist,
|
|
#[error("the reference does not match - given: '{given}' expected: '{expected}'")]
|
|
DoesNotMatch { given: Oid, expected: Oid },
|
|
}
|
|
|
|
impl Remove {
|
|
/// Guard against the `given` value using this [`Remove`].
|
|
///
|
|
/// The function will return [`Err`] if the `given` value does not pass the
|
|
/// policy the policy of the [`Remove`].
|
|
///
|
|
/// The `given` value is presumed non-existing if set to `None`, otherwise
|
|
/// it is presumed to be existing.
|
|
pub fn guard(&self, given: Option<Oid>) -> Result<(), RemoveError> {
|
|
use RemoveError::*;
|
|
|
|
match self {
|
|
Self::MustExist => {
|
|
if given.is_none() {
|
|
Err(DoesNotExist)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
},
|
|
Self::MustExistAndMatch(expected) => match given {
|
|
Some(given) if &given == expected => Ok(()),
|
|
Some(given) => Err(DoesNotMatch {
|
|
given,
|
|
expected: *expected,
|
|
}),
|
|
None => Err(DoesNotExist),
|
|
},
|
|
}
|
|
}
|
|
}
|