use derive_more::{From, Index, IndexMut};
use num_traits::Num;
use std::cmp::Ordering::Equal;
use std::ops::RangeBounds;
#[derive(Debug, Eq, PartialEq, From, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RankedCandidate<T: Clone + Eq + PartialEq> {
pub candidate: T,
pub rank: usize,
}
impl<T: Eq + PartialEq + Clone> PartialEq<(T, usize)> for RankedCandidate<T> {
fn eq(&self, other: &(T, usize)) -> bool {
self.candidate == other.0 && self.rank == other.1
}
}
#[derive(Debug, Eq, PartialEq, From, Default, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RankedWinners<T: Clone + Eq + PartialEq> {
pub winners: Vec<RankedCandidate<T>>,
pub num_winners: usize,
}
impl<T: Clone + Eq + PartialEq> RankedWinners<T> {
pub fn len(&self) -> usize {
self.winners.len()
}
pub fn is_empty(&self) -> bool {
self.winners.is_empty()
}
pub fn drain<R>(&mut self, range: R) -> std::vec::Drain<'_, RankedCandidate<T>>
where
R: RangeBounds<usize>,
{
self.winners.drain(range)
}
pub fn into_vec(self) -> Vec<RankedCandidate<T>> {
self.winners
}
pub fn all(&self) -> Vec<T> {
let mut winners = Vec::<T>::with_capacity(self.len());
for ranked in self.winners.iter() {
winners.push(ranked.candidate.clone());
}
winners
}
pub fn iter(&self) -> IterWinners<'_, T> {
IterWinners { inner: self, pos: 0 }
}
pub fn contains(&self, candidate: &T) -> bool {
for ranked in self.iter() {
if candidate == &ranked.candidate {
return true;
}
}
false
}
pub fn rank(&self, candidate: &T) -> Option<usize> {
for ranked in self.iter() {
if candidate == &ranked.candidate {
return Some(ranked.rank);
}
}
None
}
pub fn into_unranked(mut self) -> Vec<T> {
let mut all = Vec::new();
for ranked in self.drain(0..) {
all.push(ranked.candidate);
}
all
}
pub fn check_overflow(&self) -> bool {
self.len() > self.num_winners
}
pub fn overflow(&self) -> Option<Vec<T>> {
if self.check_overflow() {
let mut overflow = Vec::<T>::new();
let overflow_rank = self.winners[self.winners.len() - 1].rank;
for ranked in self.iter() {
if ranked.rank == overflow_rank {
overflow.push(ranked.candidate.clone());
}
}
Some(overflow)
} else {
None
}
}
pub(crate) fn new(num_winners: usize) -> Self {
RankedWinners {
winners: Vec::new(),
num_winners: num_winners,
}
}
pub(crate) fn push(&mut self, candidate: T, rank: usize) {
self.winners.push((candidate, rank).into());
}
pub(crate) fn sort(&mut self) {
self.winners.sort_by(|a, b| a.rank.cmp(&b.rank));
}
pub(crate) fn from_ranked(mut ranked: Vec<RankedCandidate<T>>, num_winners: usize) -> Self {
let mut winners = Self::new(num_winners);
let mut prev_rank = 0;
for ranked in ranked.drain(0..) {
if winners.len() >= num_winners && ranked.rank != prev_rank {
break;
}
winners.push(ranked.candidate, ranked.rank);
prev_rank = ranked.rank;
}
winners.sort();
winners
}
}
pub struct IterWinners<'a, T: Clone + Eq + PartialEq> {
inner: &'a RankedWinners<T>,
pos: usize,
}
impl<'a, T: Clone + Eq + PartialEq> Iterator for IterWinners<'a, T> {
type Item = &'a RankedCandidate<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.inner.winners.len() {
None
} else {
self.pos += 1;
self.inner.winners.get(self.pos - 1)
}
}
}
#[derive(Debug, Eq, PartialEq, From, Index, IndexMut, Default)]
pub(crate) struct CountedCandidates<T: Clone + Eq, C: Copy + Num + PartialOrd>(Vec<(T, C)>);
impl<T: Clone + Eq, C: Copy + Num + PartialOrd> CountedCandidates<T, C> {
pub(crate) fn new() -> Self {
CountedCandidates(Vec::new())
}
pub(crate) fn len(&self) -> usize {
self.0.len()
}
pub(crate) fn into_ranked(mut self, num_winners: usize) -> RankedWinners<T> {
let mut ranked = RankedWinners::<T>::new(num_winners);
if self.len() == 0 {
return ranked;
}
self.sort();
let mut rank = 0;
let mut prev = self.0[0].1;
for (candidate, score) in self.0.drain(0..) {
if score != prev {
if num_winners != 0 && ranked.len() >= num_winners {
return ranked;
}
rank += 1;
}
ranked.push(candidate, rank);
prev = score;
}
ranked
}
pub(crate) fn into_vec(mut self) -> Vec<(T, C)> {
self.sort();
self.0
}
pub(crate) fn push(&mut self, candidate: T, count: C) {
self.0.push((candidate, count));
}
pub(crate) fn sort(&mut self) {
self.0.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Equal));
}
}