use std::collections::BTreeMap;
use crate::git::Oid;
use super::MergeBase;
#[derive(Debug, Default)]
pub struct TagVoting {
votes: Votes,
}
impl TagVoting {
pub fn from_targets(targets: impl Iterator<Item = Oid>) -> Self {
let votes = targets.fold(Votes::default(), |mut votes, oid| {
votes.vote(oid);
votes
});
Self { votes }
}
pub fn votes(self) -> Votes {
self.votes
}
}
#[derive(Debug, Default)]
pub struct CommitVoting {
candidates: Vec<(Oid, Vec<Oid>)>,
votes: Votes,
}
impl CommitVoting {
pub fn from_targets(targets: impl Iterator<Item = Oid> + Clone) -> Self {
let ts = targets.clone();
let (candidates, votes) = targets.enumerate().fold(
(Vec::new(), Votes::default()),
|(mut candidates, mut votes), (i, oid)| {
candidates.push((oid, ts.clone().skip(i + 1).collect()));
votes.vote(oid);
(candidates, votes)
},
);
Self { candidates, votes }
}
pub fn next_candidate(&mut self) -> Option<impl Iterator<Item = (Oid, Oid)>> {
self.candidates
.pop()
.map(|(oid, others)| others.into_iter().map(move |other| (oid, other)))
}
pub fn found_merge_base(&mut self, merge_base: MergeBase) {
if let Some(oid) = merge_base.linear() {
self.votes.vote(oid)
}
}
pub fn votes(self) -> Votes {
self.votes
}
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Votes {
inner: BTreeMap<Oid, u8>,
}
impl Votes {
#[inline]
fn vote(&mut self, oid: Oid) {
let votes = self.inner.entry(oid).or_default();
*votes = votes.saturating_add(1);
}
#[inline]
pub fn candidates_past_threshold(&mut self, threshold: usize) {
self.inner.retain(|_, votes| *votes as usize >= threshold);
}
#[inline]
pub fn number_of_candidates(&self) -> usize {
self.inner.len()
}
#[inline]
pub fn candidates(&self) -> impl Iterator<Item = &Oid> {
self.inner.keys()
}
#[inline]
pub fn pop_first_candidate(&mut self) -> Option<Oid> {
self.inner.pop_first().map(|(oid, _)| oid)
}
#[inline]
pub fn max_candidate(&self) -> Option<&Oid> {
self.inner
.iter()
.max_by(|(_, x), (_, y)| x.cmp(y))
.map(|(oid, _)| oid)
}
}