use std::path::Path;
use nom::{IResult, Parser, character::char, sequence::preceded};
use rustc_hash::FxHashMap;
use crate::{
error::{HResult, HrdfError},
models::ExchangeTimeAdministration,
parsing::{
error::PResult,
helpers::{
i16_from_n_digits_parser, optional_i32_from_n_digits_parser, read_lines,
string_from_n_chars_parser,
},
},
storage::ResourceStorage,
utils::AutoIncrement,
};
fn parse_exchange_administration_row(
input: &str,
) -> IResult<&str, (Option<i32>, String, String, i16)> {
let (res, (stop_id, administration_1, administration_2, duration)) = (
optional_i32_from_n_digits_parser(7),
preceded(char(' '), string_from_n_chars_parser(6)),
preceded(char(' '), string_from_n_chars_parser(6)),
preceded(char(' '), i16_from_n_digits_parser(2)),
)
.parse(input)?;
Ok((res, (stop_id, administration_1, administration_2, duration)))
}
fn parse_line(
line: &str,
auto_increment: &AutoIncrement,
) -> PResult<(i32, ExchangeTimeAdministration)> {
let (_, (stop_id, administration_1, administration_2, duration)) =
parse_exchange_administration_row(line)?;
let id = auto_increment.next();
Ok((
id,
ExchangeTimeAdministration::new(id, stop_id, administration_1, administration_2, duration),
))
}
pub fn parse(path: &Path) -> HResult<ResourceStorage<ExchangeTimeAdministration>> {
log::info!("Parsing UMSTEIGV...");
let file = path.join("UMSTEIGV");
let lines = read_lines(&file, 0)?;
let auto_increment = AutoIncrement::new();
let exchanges = lines
.into_iter()
.enumerate()
.filter(|(_, line)| !line.trim().is_empty())
.map(|(line_number, line)| {
parse_line(&line, &auto_increment).map_err(|e| HrdfError::Parsing {
error: e,
file: String::from(file.to_string_lossy()),
line,
line_number,
})
})
.collect::<HResult<FxHashMap<i32, ExchangeTimeAdministration>>>()?;
Ok(ResourceStorage::new(exchanges))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parsing::tests::get_json_values;
use pretty_assertions::assert_eq;
#[test]
fn row_parser() {
let line = "1111135 sbg034 sbg034 01 Waldshut, Busbahnhof";
let (_, (stop_id, administration_1, administration_2, duration)) =
parse_exchange_administration_row(line).unwrap();
assert_eq!(Some(1111135), stop_id);
assert_eq!("sbg034", &administration_1);
assert_eq!("sbg034", &administration_2);
assert_eq!(1, duration);
let line = "8501008 085000 000011 10 Genève";
let (_, (stop_id, administration_1, administration_2, duration)) =
parse_exchange_administration_row(line).unwrap();
assert_eq!(Some(8501008), stop_id);
assert_eq!("085000", &administration_1);
assert_eq!("000011", &administration_2);
assert_eq!(10, duration);
let line = "@@@@@@@ 000793 000873 02";
let (_, (stop_id, administration_1, administration_2, duration)) =
parse_exchange_administration_row(line).unwrap();
assert_eq!(None, stop_id);
assert_eq!("000793", &administration_1);
assert_eq!("000873", &administration_2);
assert_eq!(2, duration);
let line = "8101236 81____ 007000 02 Feldkirch";
let (_, (stop_id, administration_1, administration_2, duration)) =
parse_exchange_administration_row(line).unwrap();
assert_eq!(Some(8101236), stop_id);
assert_eq!("81____", &administration_1);
assert_eq!("007000", &administration_2);
assert_eq!(2, duration);
}
#[test]
fn multiple_row_parsing() {
let lines = vec![
"1111135 sbg034 sbg034 01 Waldshut, Busbahnhof".to_string(),
"8501008 085000 000011 10 Genève".to_string(),
"@@@@@@@ 000793 000873 02".to_string(),
"8101236 81____ 007000 02 Feldkirch".to_string(),
];
let auto_increment = AutoIncrement::new();
let exchanges = lines
.into_iter()
.filter(|line| !line.trim().is_empty())
.map(|line| parse_line(&line, &auto_increment))
.collect::<PResult<FxHashMap<i32, ExchangeTimeAdministration>>>()
.unwrap();
let attribute = exchanges.get(&1).unwrap();
let reference = r#"
{
"id":1,
"stop_id": 1111135,
"administration_1": "sbg034",
"administration_2": "sbg034",
"duration": 1
}"#;
let (attribute, reference) = get_json_values(attribute, reference).unwrap();
assert_eq!(attribute, reference);
let attribute = exchanges.get(&2).unwrap();
let reference = r#"
{
"id":2,
"stop_id": 8501008,
"administration_1": "085000",
"administration_2": "000011",
"duration": 10
}"#;
let (attribute, reference) = get_json_values(attribute, reference).unwrap();
assert_eq!(attribute, reference);
let attribute = exchanges.get(&3).unwrap();
let reference = r#"
{
"id":3,
"stop_id": null,
"administration_1": "000793",
"administration_2": "000873",
"duration": 2
}"#;
let (attribute, reference) = get_json_values(attribute, reference).unwrap();
assert_eq!(attribute, reference);
let attribute = exchanges.get(&4).unwrap();
let reference = r#"
{
"id":4,
"stop_id": 8101236,
"administration_1": "81____",
"administration_2": "007000",
"duration": 2
}"#;
let (attribute, reference) = get_json_values(attribute, reference).unwrap();
assert_eq!(attribute, reference);
}
}