use std::collections::BTreeSet;
use std::collections::btree_set;
use std::num::NonZeroU64;
use std::sync::Arc;
use crate::quorum::QuorumIntersection;
use crate::quorum::QuorumSet;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ThresholdQuorumSet<ID> {
ids: Arc<BTreeSet<ID>>,
quorum_size: NonZeroU64,
}
impl<ID> ThresholdQuorumSet<ID> {
pub fn new(quorum_size: NonZeroU64, ids: impl Into<Arc<BTreeSet<ID>>>) -> Self {
let ids = ids.into();
Self { ids, quorum_size }
}
pub fn id_set(&self) -> &Arc<BTreeSet<ID>> {
&self.ids
}
pub fn quorum_size(&self) -> u64 {
self.quorum_size.get()
}
pub fn dual(&self) -> Option<Self> {
let id_count = self.ids.len() as u64;
let spare = id_count.checked_sub(self.quorum_size())?;
let quorum_size = NonZeroU64::MIN.saturating_add(spare);
let ids = Arc::clone(&self.ids);
Some(Self { ids, quorum_size })
}
}
impl<ID> QuorumSet for ThresholdQuorumSet<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 quorum_size = self.quorum_size();
let mut count = 0;
for id in self.ids.iter() {
if ids.clone().any(|candidate| candidate == id) {
count += 1;
if count >= quorum_size {
return true;
}
}
}
false
}
fn ids(&self) -> Self::Iter {
let ids = self.ids.as_ref().clone();
ids.into_iter()
}
}
impl<ID> QuorumIntersection<ThresholdQuorumSet<ID>> for ThresholdQuorumSet<ID>
where ID: Ord + Clone
{
fn intersects_with(&self, other: &ThresholdQuorumSet<ID>) -> Option<bool> {
let only_self = self.ids.difference(&other.ids).count() as u64;
let only_other = other.ids.difference(&self.ids).count() as u64;
let shared = self.ids.intersection(&other.ids).count() as u64;
let need_self = self.quorum_size().saturating_sub(only_self);
let need_other = other.quorum_size().saturating_sub(only_other);
let need_both = need_self.saturating_add(need_other);
Some(need_both > shared)
}
}