#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LockMode {
IntentionShared,
IntentionExclusive,
Shared,
SharedIntentionExclusive,
Exclusive,
}
impl LockMode {
#[inline]
const fn index(self) -> usize {
match self {
LockMode::IntentionShared => 0,
LockMode::IntentionExclusive => 1,
LockMode::Shared => 2,
LockMode::SharedIntentionExclusive => 3,
LockMode::Exclusive => 4,
}
}
#[inline]
#[must_use]
pub const fn compatible_with(self, other: LockMode) -> bool {
const COMPAT: [[bool; 5]; 5] = [
[true, true, true, true, false], [true, true, false, false, false], [true, false, true, false, false], [true, false, false, false, false], [false, false, false, false, false], ];
COMPAT[self.index()][other.index()]
}
#[inline]
#[must_use]
pub const fn join(self, other: LockMode) -> LockMode {
use LockMode::{
Exclusive, IntentionExclusive, IntentionShared, Shared, SharedIntentionExclusive,
};
const JOIN: [[LockMode; 5]; 5] = [
[
IntentionShared,
IntentionExclusive,
Shared,
SharedIntentionExclusive,
Exclusive,
],
[
IntentionExclusive,
IntentionExclusive,
SharedIntentionExclusive,
SharedIntentionExclusive,
Exclusive,
],
[
Shared,
SharedIntentionExclusive,
Shared,
SharedIntentionExclusive,
Exclusive,
],
[
SharedIntentionExclusive,
SharedIntentionExclusive,
SharedIntentionExclusive,
SharedIntentionExclusive,
Exclusive,
],
[Exclusive, Exclusive, Exclusive, Exclusive, Exclusive],
];
JOIN[self.index()][other.index()]
}
#[inline]
#[must_use]
pub const fn covers(self, other: LockMode) -> bool {
self.join(other) as u8 == self as u8
}
#[inline]
#[must_use]
pub const fn is_exclusive(self) -> bool {
matches!(self, LockMode::Exclusive)
}
#[inline]
#[must_use]
pub const fn is_intention(self) -> bool {
matches!(
self,
LockMode::IntentionShared
| LockMode::IntentionExclusive
| LockMode::SharedIntentionExclusive
)
}
}
#[cfg(test)]
mod tests {
use super::LockMode::{
self, Exclusive, IntentionExclusive, IntentionShared, Shared, SharedIntentionExclusive,
};
const ALL: [LockMode; 5] = [
IntentionShared,
IntentionExclusive,
Shared,
SharedIntentionExclusive,
Exclusive,
];
#[test]
fn test_compatibility_matches_standard_mgl_matrix() {
let expected = [
[true, true, true, true, false],
[true, true, false, false, false],
[true, false, true, false, false],
[true, false, false, false, false],
[false, false, false, false, false],
];
for (i, a) in ALL.iter().enumerate() {
for (j, b) in ALL.iter().enumerate() {
assert_eq!(
a.compatible_with(*b),
expected[i][j],
"compat({a:?}, {b:?})"
);
}
}
}
#[test]
fn test_compatible_is_symmetric() {
for a in ALL {
for b in ALL {
assert_eq!(a.compatible_with(b), b.compatible_with(a), "{a:?} vs {b:?}");
}
}
}
#[test]
fn test_exclusive_incompatible_with_all() {
for m in ALL {
assert!(!Exclusive.compatible_with(m));
assert!(!m.compatible_with(Exclusive));
}
}
#[test]
fn test_intention_shared_compatible_with_all_but_exclusive() {
for m in ALL {
assert_eq!(IntentionShared.compatible_with(m), m != Exclusive);
}
}
#[test]
fn test_join_is_commutative() {
for a in ALL {
for b in ALL {
assert_eq!(a.join(b), b.join(a), "join({a:?}, {b:?})");
}
}
}
#[test]
fn test_join_is_associative() {
for a in ALL {
for b in ALL {
for c in ALL {
assert_eq!(a.join(b).join(c), a.join(b.join(c)));
}
}
}
}
#[test]
fn test_join_idempotent() {
for m in ALL {
assert_eq!(m.join(m), m);
}
}
#[test]
fn test_join_examples() {
assert_eq!(Shared.join(IntentionExclusive), SharedIntentionExclusive);
assert_eq!(IntentionShared.join(Shared), Shared);
assert_eq!(IntentionShared.join(IntentionExclusive), IntentionExclusive);
assert_eq!(Shared.join(Exclusive), Exclusive);
assert_eq!(SharedIntentionExclusive.join(Exclusive), Exclusive);
}
#[test]
fn test_covers_is_join_equals_self() {
for a in ALL {
for b in ALL {
assert_eq!(a.covers(b), a.join(b) == a, "covers({a:?}, {b:?})");
}
}
}
#[test]
fn test_exclusive_covers_everything() {
for m in ALL {
assert!(Exclusive.covers(m));
}
}
#[test]
fn test_six_covers_its_components() {
assert!(SharedIntentionExclusive.covers(Shared));
assert!(SharedIntentionExclusive.covers(IntentionExclusive));
assert!(SharedIntentionExclusive.covers(IntentionShared));
assert!(!SharedIntentionExclusive.covers(Exclusive));
}
#[test]
fn test_covers_reflexive() {
for m in ALL {
assert!(m.covers(m));
}
}
#[test]
fn test_is_exclusive_and_is_intention() {
assert!(Exclusive.is_exclusive());
assert!(!Shared.is_exclusive());
for m in [
IntentionShared,
IntentionExclusive,
SharedIntentionExclusive,
] {
assert!(m.is_intention());
}
assert!(!Shared.is_intention());
assert!(!Exclusive.is_intention());
}
#[test]
fn test_two_compatible_modes_join_below_any_conflict() {
for a in ALL {
for b in ALL {
if a.compatible_with(b) {
assert!(!(a.is_exclusive() && b.is_exclusive()));
}
}
}
}
}