Return Result from CSP parse_reader, better error messages
This commit is contained in:
parent
71dc671c34
commit
e78d06289a
|
@ -28,6 +28,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
|
@ -711,6 +717,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
|||
name = "opentally"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
"clap",
|
||||
"console_error_panic_hook",
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||
crate-type = ["lib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.44"
|
||||
csv = "1.1.6"
|
||||
derive_builder = "0.10.2"
|
||||
derive_more = "0.99.14"
|
||||
|
|
|
@ -113,7 +113,7 @@ pub fn main(mut cmd_opts: SubcmdOptions) -> Result<(), i32> {
|
|||
}
|
||||
"csp" => {
|
||||
let file = File::open(cmd_opts.infile).expect("IO Error");
|
||||
election = parser::csp::parse_reader(file, cmd_opts.require_1, cmd_opts.require_sequential, cmd_opts.require_strict_order);
|
||||
election = parser::csp::parse_reader(file, cmd_opts.require_1, cmd_opts.require_sequential, cmd_opts.require_strict_order).expect("Syntax Error");
|
||||
}
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
use crate::election::{Ballot, Candidate, Election};
|
||||
use crate::numbers::Number;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use csv::ReaderBuilder;
|
||||
use itertools::Itertools;
|
||||
|
||||
|
@ -25,7 +26,7 @@ use std::collections::HashMap;
|
|||
use std::io::Read;
|
||||
|
||||
/// Parse the given CSP file
|
||||
pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequential: bool, require_strict_order: bool) -> Election<N> {
|
||||
pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequential: bool, require_strict_order: bool) -> Result<Election<N>> {
|
||||
// Read CSV file
|
||||
let mut reader = ReaderBuilder::new()
|
||||
.has_headers(true)
|
||||
|
@ -33,14 +34,14 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
|
||||
// Read candidates
|
||||
let mut candidates = Vec::new();
|
||||
let mut idx_map = HashMap::new(); // Map csp index -> candidates index
|
||||
let mut col_map = HashMap::new(); // Map csp column -> candidates index
|
||||
|
||||
for (i, cand_name) in reader.headers().expect("Syntax Error").into_iter().enumerate() {
|
||||
for (i, cand_name) in reader.headers()?.into_iter().enumerate() {
|
||||
if cand_name == "$mult" {
|
||||
continue;
|
||||
}
|
||||
|
||||
idx_map.insert(i, candidates.len());
|
||||
col_map.insert(i, candidates.len());
|
||||
candidates.push(Candidate {
|
||||
name: cand_name.to_string(),
|
||||
});
|
||||
|
@ -49,22 +50,22 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
// Read ballots
|
||||
let mut ballots = Vec::new();
|
||||
|
||||
for record in reader.into_records() {
|
||||
let record = record.expect("Syntax Error");
|
||||
for (csv_row, record) in reader.into_records().enumerate() {
|
||||
let record = record?;
|
||||
|
||||
let mut value = N::one();
|
||||
|
||||
// Record preferences
|
||||
let mut preferences = Vec::new(); // Vec of (ranking, candidate index)
|
||||
for (csv_index, preference) in record.into_iter().enumerate() {
|
||||
match idx_map.get(&csv_index) {
|
||||
for (csv_col, preference) in record.into_iter().enumerate() {
|
||||
match col_map.get(&csv_col) {
|
||||
Some(cand_index) => {
|
||||
// Preference
|
||||
if preference.len() == 0 || preference == "-" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let preference: usize = preference.parse().expect("Syntax Error");
|
||||
let preference: usize = preference.parse().context(format!("Invalid number \"{}\" at row {}, column {}", preference, csv_row + 2, csv_col + 1))?;
|
||||
if preference == 0 {
|
||||
continue;
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
}
|
||||
None => {
|
||||
// $mult column
|
||||
let mult: usize = preference.parse().expect("Syntax Error");
|
||||
let mult: usize = preference.parse().context(format!("Invalid number \"{}\" at row {}, column {}", preference, csv_row + 2, csv_col + 1))?;
|
||||
if mult == 1 {
|
||||
continue;
|
||||
}
|
||||
|
@ -131,7 +132,7 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
});
|
||||
}
|
||||
|
||||
return Election {
|
||||
return Ok(Election {
|
||||
name: String::new(),
|
||||
seats: 0,
|
||||
candidates: candidates,
|
||||
|
@ -139,5 +140,5 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
ballots: ballots,
|
||||
total_votes: None,
|
||||
constraints: None,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue