use std::collections::BTreeSet;
use std::collections::btree_set;
use crate::quorum::QuorumBridge;
use crate::quorum::QuorumIntersection;
use crate::quorum::QuorumSet;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Joint<Q> {
rules: Vec<Q>,
}
impl<Q> Joint<Q> {
pub fn new(rules: impl IntoIterator<Item = Q>) -> Self {
let rules = rules.into_iter().collect();
Self { rules }
}
pub fn rules(&self) -> &[Q] {
&self.rules
}
}
impl<Q> Default for Joint<Q> {
fn default() -> Self {
Self { rules: vec![] }
}
}
impl<Q> QuorumSet for Joint<Q>
where
Q: QuorumSet,
Q::Id: Ord,
{
type Id = Q::Id;
type Iter = btree_set::IntoIter<Q::Id>;
fn is_quorum<'a, I>(&self, ids: I) -> bool
where
Self::Id: 'a,
I: Iterator<Item = &'a Self::Id> + Clone,
{
if self.rules.is_empty() {
return false;
}
for rule in &self.rules {
if !rule.is_quorum(ids.clone()) {
return false;
}
}
true
}
fn ids(&self) -> Self::Iter {
let mut ids = BTreeSet::new();
for rule in &self.rules {
ids.extend(rule.ids());
}
ids.into_iter()
}
}
impl<Q> QuorumIntersection<Joint<Q>> for Joint<Q>
where
Q: QuorumIntersection<Q>,
Q::Id: Ord,
{
fn intersects_with(&self, other: &Joint<Q>) -> Option<bool> {
let either_is_empty = self.rules.is_empty() || other.rules.is_empty();
if either_is_empty {
return Some(true);
}
let both_uniform = self.rules.len() == 1 && other.rules.len() == 1;
if both_uniform {
return self.rules[0].intersects_with(&other.rules[0]);
}
for a in &self.rules {
for b in &other.rules {
let intersects = a.intersects_with(b);
if intersects == Some(true) {
return Some(true);
}
}
}
None
}
}
impl<Q> QuorumBridge<Joint<Q>> for Joint<Q>
where
Q: QuorumSet + Clone,
Q::Id: Ord,
{
fn joint_with(&self, other: Joint<Q>) -> Self {
if self.rules.is_empty() || other.rules.is_empty() {
return Self::default();
}
let mut rules = self.rules.clone();
rules.extend(other.rules);
Self { rules }
}
}