, opts: &stv::STVOptions) -> String {
let mut result = String::from("Count computed by OpenTally (revision ");
result.push_str(crate::VERSION);
let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value });
result.push_str(&format!(r#"). Read {} ballots from ‘{}’ for election ‘{}’. There are {} candidates for {} vacancies. Counting using options {}.
"#, total_ballots, filename, election.name, election.candidates.len(), election.seats, opts.describe::()));
return result;
}
fn update_results_table(stage_num: usize, state: &CountState, opts: &stv::STVOptions) -> Array {
let result = Array::new();
result.push(&format!(r#"{} | "#, stage_num).into());
result.push(&format!(r#"{} | "#, state.kind.unwrap_or("")).into());
result.push(&format!(r#"{} | "#, state.title).into());
for candidate in state.election.candidates.iter() {
let count_card = state.candidates.get(candidate).unwrap();
if count_card.state == stv::CandidateState::ELECTED {
result.push(&format!(r#"{} | "#, pp(&count_card.transfers, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&count_card.votes, opts.pp_decimals)).into());
} else if count_card.state == stv::CandidateState::EXCLUDED {
result.push(&format!(r#"{} | "#, pp(&count_card.transfers, opts.pp_decimals)).into());
if count_card.votes.is_zero() {
result.push(&r#"Ex | "#.into());
} else {
result.push(&format!(r#"{} | "#, pp(&count_card.votes, opts.pp_decimals)).into());
}
} else {
result.push(&format!(r#"{} | "#, pp(&count_card.transfers, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&count_card.votes, opts.pp_decimals)).into());
}
}
result.push(&format!(r#"{} | "#, pp(&state.exhausted.transfers, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&state.exhausted.votes, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&state.loss_fraction.transfers, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&state.loss_fraction.votes, opts.pp_decimals)).into());
// Calculate total votes
let mut total_vote = state.candidates.values().fold(N::zero(), |acc, cc| { acc + &cc.votes });
total_vote += &state.exhausted.votes;
total_vote += &state.loss_fraction.votes;
result.push(&format!(r#"{} | "#, pp(&total_vote, opts.pp_decimals)).into());
result.push(&format!(r#"{} | "#, pp(&state.quota, opts.pp_decimals)).into());
return result;
}
fn update_stage_comments(state: &CountState) -> String {
return state.logger.render().join(" ");
}
fn finalise_results_table(state: &CountState) -> Array {
let result = Array::new();
// Header rows
result.push(&r#" | "#.into());
result.push(&"".into());
result.push(&"".into());
// Candidate states
for candidate in state.election.candidates.iter() {
let count_card = state.candidates.get(candidate).unwrap();
if count_card.state == stv::CandidateState::ELECTED {
result.push(&format!(r#"ELECTED {} | "#, count_card.order_elected).into());
} else if count_card.state == stv::CandidateState::EXCLUDED {
result.push(&format!(r#"Excluded {} | "#, -count_card.order_elected).into());
} else {
result.push(&r#" | "#.into());
}
result.push(&"".into());
}
return result;
}
fn final_result_summary(state: &CountState) -> String {
let mut result = String::from("Count complete. The winning candidates are, in order of election:
");
let mut winners = Vec::new();
for (candidate, count_card) in state.candidates.iter() {
if count_card.state == CandidateState::ELECTED {
winners.push((candidate, count_card.order_elected));
}
}
winners.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
for (winner, _) in winners.into_iter() {
result.push_str(&format!("- {}
", winner.name));
}
result.push_str("
");
return result;
}
fn pp(n: &N, dps: usize) -> String {
if n.is_zero() {
return "".to_string();
}
let mut raw = format!("{:.dps$}", n, dps=dps);
if raw.contains('.') {
raw = raw.replacen(".", ".", 1);
raw.push_str("");
}
if raw.starts_with('-') {
raw = raw.replacen("-", "−", 1);
}
return raw;
}