use std::collections::BTreeSet;
use std::collections::btree_set;
use crate::quorum::QuorumIntersection;
use crate::quorum::QuorumSet;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExplicitQuorumSet<ID> {
quorums: Vec<BTreeSet<ID>>,
}
impl<ID> ExplicitQuorumSet<ID>
where ID: Ord + Clone
{
pub fn new<I>(quorums: I) -> Option<Self>
where I: IntoIterator<Item = BTreeSet<ID>> {
let mut quorums: Vec<BTreeSet<ID>> = quorums.into_iter().collect();
let has_empty_quorum = quorums.iter().any(|quorum| quorum.is_empty());
if has_empty_quorum {
return None;
}
quorums.sort();
quorums.dedup();
let mut minimal = Vec::new();
for quorum in &quorums {
let holds_other =
quorums.iter().any(|other| other != quorum && other.is_subset(quorum));
if holds_other {
continue;
}
minimal.push(quorum.clone());
}
let rule = Self { quorums: minimal };
Some(rule)
}
pub fn quorums(&self) -> &[BTreeSet<ID>] {
&self.quorums
}
pub fn disjoint_quorums<'a>(
&'a self,
other: &'a Self,
) -> Option<(&'a BTreeSet<ID>, &'a BTreeSet<ID>)> {
for quorum in &self.quorums {
for other_quorum in &other.quorums {
if quorum.is_disjoint(other_quorum) {
return Some((quorum, other_quorum));
}
}
}
None
}
}
impl<ID> QuorumSet for ExplicitQuorumSet<ID>
where ID: Ord + Clone
{
type Id = ID;
type Iter = btree_set::IntoIter<ID>;
fn is_quorum<'a, I>(&self, ids: I) -> bool
where
ID: 'a,
I: Iterator<Item = &'a ID> + Clone,
{
let candidates: BTreeSet<&ID> = ids.collect();
for quorum in &self.quorums {
let holds_quorum = quorum.iter().all(|id| candidates.contains(id));
if holds_quorum {
return true;
}
}
false
}
fn ids(&self) -> Self::Iter {
let mut ids = BTreeSet::new();
for quorum in &self.quorums {
ids.extend(quorum.iter().cloned());
}
ids.into_iter()
}
}
impl<ID> QuorumIntersection<ExplicitQuorumSet<ID>> for ExplicitQuorumSet<ID>
where ID: Ord + Clone
{
fn intersects_with(&self, other: &ExplicitQuorumSet<ID>) -> Option<bool> {
let disjoint = self.disjoint_quorums(other);
Some(disjoint.is_none())
}
}