vote-counter/src/main.rs
2023-09-01 17:01:31 +10:00

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);
}
}
}