use std::collections::BTreeSet;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use serde::Serialize;
use crate::core::{Candidate, Id};
pub trait Outcome: Send + Sync + Clone + Serialize + Debug + Display + Eq + Hash {
fn winners(&self) -> Vec<&str>;
}
impl Outcome for SingleWinner {
fn winners(&self) -> Vec<&str> {
match self {
Self::Win(candidate) => vec![candidate.name()],
Self::Tie(candidates) => candidates.iter().map(Candidate::name).collect(),
Self::None => vec![],
}
}
}
impl Outcome for MultiWinner {
fn winners(&self) -> Vec<&str> {
match self {
Self::Elected(candidates) => candidates.iter().map(Candidate::name).collect(),
Self::None => vec![],
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum SingleWinner {
Win(Candidate),
Tie(BTreeSet<Candidate>),
None,
}
impl SingleWinner {
#[must_use]
pub fn win(candidates: &[Candidate], id: Id) -> Self {
Self::Win(candidates.iter().find(|c| c.id() == id).unwrap().to_owned())
}
#[must_use]
pub fn tie(candidates: &[Candidate], ids: &[Id]) -> Self {
Self::Tie(
ids.iter()
.map(|id| {
candidates
.iter()
.find(|c| &c.id() == id)
.unwrap()
.to_owned()
})
.collect(),
)
}
#[must_use]
pub const fn none() -> Self {
Self::None
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum MultiWinner {
Elected(BTreeSet<Candidate>),
None,
}
impl MultiWinner {
#[must_use]
pub fn seats(candidates: &[Candidate], ids: &[Id]) -> Self {
Self::Elected(
ids.iter()
.map(|id| {
candidates
.iter()
.find(|c| &c.id() == id)
.unwrap()
.to_owned()
})
.collect(),
)
}
#[must_use]
pub const fn none() -> Self {
Self::None
}
}
impl Display for SingleWinner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Win(candidate) => write!(f, "Win({})", candidate.name()),
Self::Tie(candidates) => {
write!(
f,
"Tie({})",
candidates
.iter()
.map(Candidate::name)
.collect::<Vec<_>>()
.join(", ")
)
}
Self::None => write!(f, "None"),
}
}
}
impl Display for MultiWinner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Elected(candidates) => {
write!(
f,
"MultiWinner({})",
candidates
.iter()
.map(|c| c.name().to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
Self::None => write!(f, "MultiWinner(None)"),
}
}
}