use crate::tally::Metadata;
pub struct GenericOutcome<'a> {
winners: Vec<u32>,
withdrawn: Vec<u32>,
sealed: bool,
candidates: u32,
meta: &'a Metadata,
}
impl<'a> GenericOutcome<'a> {
pub fn new<I, J>(
winners: I,
withdrawn: J,
candidates: u32,
sealed: bool,
meta: &'a Metadata,
) -> GenericOutcome<'a>
where
I: IntoIterator<Item = u32>,
J: IntoIterator<Item = u32>,
{
GenericOutcome {
winners: winners.into_iter().collect(),
withdrawn: withdrawn.into_iter().collect(),
candidates,
sealed,
meta,
}
}
}
impl<'a> Outcome for GenericOutcome<'a> {
fn meta(&self) -> &Metadata {
self.meta
}
fn deterministic(&self) -> bool {
self.sealed
}
fn candidate_count(&self) -> usize {
self.candidates as usize
}
fn elected_count(&self) -> usize {
self.winners.len()
}
fn elected(&self) -> CandidateIterator {
CandidateIterator {
wrapped: self.winners.iter(),
}
}
fn winner(&self) -> Option<u32> {
self.winners.first().cloned()
}
fn withdrawn_count(&self) -> usize {
self.withdrawn.len()
}
fn withdrawn(&self) -> CandidateIterator {
CandidateIterator {
wrapped: self.winners.iter(),
}
}
}
pub struct CandidateIterator<'a> {
wrapped: std::slice::Iter<'a, u32>,
}
impl<'a> Iterator for CandidateIterator<'a> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
self.wrapped.next().cloned()
}
}
fn get_meta_name_or_placeholder(meta: &Metadata, who: u32) -> String {
if let Some(ans) = meta.get_name(who) {
ans.clone()
} else {
format!("Candidate {}", who + 1)
}
}
pub struct NamesIterator<'a> {
base: CandidateIterator<'a>,
meta: &'a Metadata,
}
impl<'a> Iterator for NamesIterator<'a> {
type Item = String;
fn next(&mut self) -> Option<String> {
if let Some(x) = self.base.next() {
Some(get_meta_name_or_placeholder(self.meta, x))
} else {
None
}
}
}
pub trait Outcome {
fn meta(&self) -> &Metadata;
fn deterministic(&self) -> bool;
fn elected(&self) -> CandidateIterator;
fn elected_count(&self) -> usize {
self.elected().count()
}
fn candidate_count(&self) -> usize;
fn elected_names(&self) -> NamesIterator {
NamesIterator {
base: self.elected(),
meta: self.meta(),
}
}
fn winner(&self) -> Option<u32> {
let mut ci = self.elected();
match (ci.next(), ci.next()) {
(Some(winner), None) => Some(winner),
_ => None,
}
}
fn winner_name(&self) -> Option<String> {
self.winner()
.map(|x| get_meta_name_or_placeholder(self.meta(), x))
}
fn withdrawn(&self) -> CandidateIterator;
fn withdrawn_count(&self) -> usize {
self.withdrawn().count()
}
fn withdrawn_names(&self) -> NamesIterator {
NamesIterator {
base: self.withdrawn(),
meta: self.meta(),
}
}
}
use std::fmt;
impl<'a> fmt::Debug for GenericOutcome<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<'a> fmt::Display for GenericOutcome<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Election outcome")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Minimax, VoteMatrix};
#[test]
fn placeholder_names() {
let x = VoteMatrix::with_vector_bycol(&vec![1, 2, 3, 4, 5, 6]);
let outcome = Minimax::new(&x).run().unwrap();
assert_eq!(outcome.winner_name().unwrap(), "Candidate 1");
}
}