wybr 0.0.6

Collection of preferential voting methods
Documentation
//! Generic outcome for election methods
//!
//! All the election methods return an object which implements the `Outcome` trait.

use crate::tally::Metadata;

///Multi-winner election outcome
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(),
        }
    }
}

///Iterator over the IDs of elected candidates
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)
    }
}

///Iterator over the names of elected candidates
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
        }
    }
}

///Trait representing generic output from an election method
pub trait Outcome {
    ///Reference to the election metadata
    fn meta(&self) -> &Metadata;
    ///Specify whether the election was deterministic
    ///
    ///In other words, returns `false` whenever PRNG was used to settle the election.
    ///
    ///In case of ranked pairs method, there is a chance for false negatives, i.e. elections
    ///deemed not deterministic while there were.
    ///
    ///In case of Meek and Warren methods, determinisms may also depend on the numerical issues
    ///due to an use of fixed point arithmetic.
    fn deterministic(&self) -> bool;
    ///Return iterator of IDs of elected candidates
    fn elected(&self) -> CandidateIterator;
    fn elected_count(&self) -> usize {
        self.elected().count()
    }
    fn candidate_count(&self) -> usize;
    ///Return iterator of elected candidate names
    ///
    ///When there is no name for some candidate (or no names at all), placeholder names featuring
    ///1-based indices of candidates will be generated.
    fn elected_names(&self) -> NamesIterator {
        NamesIterator {
            base: self.elected(),
            meta: self.meta(),
        }
    }
    ///Return a single winner ID, if there is one, that is either the election scheme is single
    ///winner one or there is one seat in multi-winner election
    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))
    }
    ///Return iterator of IDs of withdrawn candidates
    fn withdrawn(&self) -> CandidateIterator;
    fn withdrawn_count(&self) -> usize {
        self.withdrawn().count()
    }
    ///Return iterator of names of withdrawn candidates
    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");
    }
}