78 lines
1.7 KiB
Rust
Executable File
78 lines
1.7 KiB
Rust
Executable File
mod ballot_box;
|
|
mod reporting;
|
|
mod candidates;
|
|
mod ballot;
|
|
|
|
use ballot_box::BallotBox;
|
|
use ballot_box::CountStatus::*;
|
|
|
|
use std::path;
|
|
use std::process;
|
|
|
|
use clap::Parser;
|
|
|
|
/// Adjusts threshold to be within permitted range, warning the user.
|
|
fn adjust_threshold(threshold : f64) -> f64 {
|
|
reporting::threshold_squash(threshold);
|
|
if threshold < 0.0 {
|
|
0.0
|
|
}
|
|
else if threshold > 1.0 {
|
|
1.0
|
|
}
|
|
else {
|
|
threshold
|
|
}
|
|
}
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[clap(author, about, version)]
|
|
struct Args {
|
|
/// Path to the CSV containing the ballots.
|
|
#[clap()]
|
|
path : path::PathBuf,
|
|
|
|
/// Threshold to win (from 0.0 to 1.0).
|
|
#[clap(long, short, default_value = "0.5")]
|
|
threshold : f64,
|
|
|
|
/// Generate report of counting.
|
|
#[clap(long, takes_value = false)]
|
|
report : bool,
|
|
}
|
|
|
|
/// Primary entry point to vote counting algorithms.
|
|
fn count(mut args : Args) -> Result<(), csv::Error> {
|
|
|
|
args.threshold = adjust_threshold(args.threshold);
|
|
|
|
let mut ballot_box = BallotBox::from_file(&args.path, args.report)?;
|
|
|
|
let winner = loop {
|
|
match ballot_box.status(args.threshold, args.report) {
|
|
Winner(winner) => break Some(winner),
|
|
Tie => break None,
|
|
Runoff(to_eliminated) => ballot_box.runoff(to_eliminated),
|
|
Promotion(to_promote) => ballot_box.promote(to_promote),
|
|
}
|
|
};
|
|
|
|
reporting::winner(winner, &ballot_box.candidates);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
let args = Args::parse();
|
|
|
|
match count(args) {
|
|
Ok(_) => {
|
|
process::exit(exitcode::OK);
|
|
},
|
|
Err(error) => {
|
|
reporting::csv_error(error);
|
|
process::exit(exitcode::DATAERR);
|
|
}
|
|
}
|
|
}
|