Integrate with clap for CLI argument parsing

This commit is contained in:
RunasSudo 2021-05-28 20:42:01 +10:00
parent efc7588c09
commit 637884cdbf
No known key found for this signature in database
GPG Key ID: 7234E476BF21C61A
3 changed files with 207 additions and 16 deletions

165
Cargo.lock generated
View File

@ -12,6 +12,41 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "822d7d63e0c0260a050f6b1f0d316f5c79b9eab830aca526ed904e1011bd64ca"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "clap"
version = "3.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
dependencies = [
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "clap_derive"
version = "3.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gmp-mpfr-sys"
version = "1.4.5"
@ -22,6 +57,37 @@ dependencies = [
"winapi",
]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "heck"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "indexmap"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.95"
@ -41,10 +107,59 @@ dependencies = [
name = "opentally"
version = "0.1.0"
dependencies = [
"clap",
"num-traits",
"rug",
]
[[package]]
name = "os_str_bytes"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rug"
version = "1.12.0"
@ -56,6 +171,56 @@ dependencies = [
"libc",
]
[[package]]
name = "syn"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "textwrap"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "winapi"
version = "0.3.9"

View File

@ -11,3 +11,8 @@ num-traits = "0.2"
version = "1.12"
default-features = false
features = ["integer", "rational", "float"]
[dependencies.clap]
version = "3.0.0-beta.2"
default-features = false
features = ["std", "derive"]

View File

@ -22,13 +22,33 @@ mod stv;
use crate::election::{CandidateState, CountState, CountStateOrRef, Election, StageResult};
use crate::numbers::{Number, NumType};
use std::env;
use clap::Clap;
use std::fs::File;
use std::io::{self, BufRead};
const DECIMAL_PLACES: usize = 0;
#[derive(Clap)]
struct Opts {
#[clap(subcommand)]
command: Command,
}
fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>) {
#[derive(Clap)]
enum Command {
STV(STV),
}
/// Count a single transferable vote (STV) election
#[derive(Clap)]
struct STV {
/// Path to the BLT file to be counted
filename: String,
/// Print votes to specified decimal places in results report
#[clap(long, default_value="2")]
pp_decimals: usize,
}
fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>, cmd_opts: &STV) {
println!("{}. {}", stage_num, result.title);
println!("{}", result.logs.join(" "));
@ -41,27 +61,28 @@ fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>) {
//for (candidate, count_card) in candidates.into_iter().rev() {
for (candidate, count_card) in candidates {
if count_card.state == CandidateState::ELECTED {
println!("- {}: {:.dps$} ({:.dps$}) - ELECTED {}", candidate.name, count_card.votes, count_card.transfers, count_card.order_elected, dps=DECIMAL_PLACES);
println!("- {}: {:.dps$} ({:.dps$}) - ELECTED {}", candidate.name, count_card.votes, count_card.transfers, count_card.order_elected, dps=cmd_opts.pp_decimals);
} else if count_card.state == CandidateState::EXCLUDED {
println!("- {}: {:.dps$} ({:.dps$}) - Excluded {}", candidate.name, count_card.votes, count_card.transfers, -count_card.order_elected, dps=DECIMAL_PLACES);
println!("- {}: {:.dps$} ({:.dps$}) - Excluded {}", candidate.name, count_card.votes, count_card.transfers, -count_card.order_elected, dps=cmd_opts.pp_decimals);
} else {
println!("- {}: {:.dps$} ({:.dps$})", candidate.name, count_card.votes, count_card.transfers, dps=DECIMAL_PLACES);
println!("- {}: {:.dps$} ({:.dps$})", candidate.name, count_card.votes, count_card.transfers, dps=cmd_opts.pp_decimals);
}
}
println!("Quota: {:.dps$}", result.state.as_ref().quota, dps=DECIMAL_PLACES);
println!("Quota: {:.dps$}", result.state.as_ref().quota, dps=cmd_opts.pp_decimals);
println!("");
}
fn main() {
// Read arguments
let file_name = env::args().skip(1).next().expect("First argument must be path to BLT file");
let should_clone_state = false;
// Read arguments
let opts: Opts = Opts::parse();
let Command::STV(cmd_opts) = opts.command;
// Read BLT file
let file = File::open(file_name).expect("IO Error");
let file = File::open(&cmd_opts.filename).expect("IO Error");
let lines = io::BufReader::new(file).lines();
let election: Election<NumType> = Election::from_blt(lines);
@ -80,7 +101,7 @@ fn main() {
logs: vec!["First preferences distributed."],
state: if should_clone_state { CountStateOrRef::State(state.clone()) } else { CountStateOrRef::Ref(&state) },
};
print_stage(1, &result);
print_stage(1, &result, &cmd_opts);
let mut stage_num = 1;
@ -101,7 +122,7 @@ fn main() {
logs: vec!["Continuing exclusion."],
state: if should_clone_state { CountStateOrRef::State(state.clone()) } else { CountStateOrRef::Ref(&state) },
};
print_stage(stage_num, &result);
print_stage(stage_num, &result, &cmd_opts);
continue;
}
@ -113,7 +134,7 @@ fn main() {
logs: vec!["Surplus distributed."],
state: if should_clone_state { CountStateOrRef::State(state.clone()) } else { CountStateOrRef::Ref(&state) },
};
print_stage(stage_num, &result);
print_stage(stage_num, &result, &cmd_opts);
continue;
}
@ -125,7 +146,7 @@ fn main() {
logs: vec!["Bulk election."],
state: if should_clone_state { CountStateOrRef::State(state.clone()) } else { CountStateOrRef::Ref(&state) },
};
print_stage(stage_num, &result);
print_stage(stage_num, &result, &cmd_opts);
continue;
}
@ -137,7 +158,7 @@ fn main() {
logs: vec!["Candidate excluded."],
state: if should_clone_state { CountStateOrRef::State(state.clone()) } else { CountStateOrRef::Ref(&state) },
};
print_stage(stage_num, &result);
print_stage(stage_num, &result, &cmd_opts);
continue;
}