From b82c40d4ab2ac52e447a82b545d06d7b9f665157 Mon Sep 17 00:00:00 2001 From: 132nd-Professor <132nd-Professor> Date: Fri, 12 Aug 2022 16:19:42 +0200 Subject: [PATCH] more error handling --- src/main.rs | 2 +- src/processor.rs | 93 ++++++++++++++++++++++++++++++++++++------------ src/reader.rs | 7 ++-- 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/main.rs b/src/main.rs index cc6517f..67e5638 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ fn main() { fn main_inner() -> Result<(), Box> { let (input_filename, is_zip) = reader::find_input_file()?; println!("Processing {}", input_filename); - let lines = reader::read_data(&input_filename, is_zip); + let lines = reader::read_data(&input_filename, is_zip)?; let (header, body) = processor::split_into_header_and_body(&lines); let coalition_per_line = processor::divide_body_by_coalition(body); diff --git a/src/processor.rs b/src/processor.rs index b357d2b..d664822 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -1,31 +1,45 @@ +use std::error::Error; +use std::fmt::Display; use std::hash::Hash; use crate::constants::{COMMENT, MINUS}; use crate::tacview::{Coalition, CoalitionIDs}; -pub fn split_into_header_and_body>(lines: &[S]) -> (&[S], &[S]) { +pub fn split_into_header_and_body(lines: &[S]) -> Result<(&[S], &[S]), ProcessingError> +where + S: AsRef, +{ let mut i = 0; for line in lines { - if line.as_ref().chars().next().expect("malformed line") == COMMENT { + if line + .as_ref() + .chars() + .next() + .ok_or(ProcessingError::LineIsEmptyError)? + == COMMENT + { break; } i += 1; } - (&lines[..i], &lines[i..]) + Ok((&lines[..i], &lines[i..])) } -pub fn divide_body_by_coalition + Hash + Eq>(body: &[S]) -> Vec { +pub fn divide_body_by_coalition(body: &[S]) -> Result, Box> +where + S: AsRef + Hash + Eq, +{ let mut result = vec![]; let mut coalition_ids: CoalitionIDs = CoalitionIDs::new(); let mut old_line = Line::default(); for line_s in body { - let processed = Line::process_line(old_line, line_s, &mut coalition_ids); + let processed = Line::process_line(old_line, line_s, &mut coalition_ids)?; result.push(processed.coalition.clone()); old_line = processed; } - result + Ok(result) } struct Line { @@ -39,17 +53,19 @@ impl Line { old_line: Line, current_line: &'a S, coalition_ids: &mut CoalitionIDs<'a>, - ) -> Self { + ) -> Result { let line_type = match old_line.continued { true => old_line.line_type, - false => LineType::find_type(current_line), + false => LineType::find_type(current_line)?, }; match line_type { - LineType::Telemetry => Line::from_content(line_type, current_line, coalition_ids), - LineType::Timestamp => Line::new(line_type, false, Coalition::All), - LineType::Destruction => Line::from_content(line_type, current_line, coalition_ids), - LineType::Unknown => panic!(""), + LineType::Telemetry => Ok(Line::from_content(line_type, current_line, coalition_ids)?), + LineType::Timestamp => Ok(Line::new(line_type, false, Coalition::All)), + LineType::Destruction => { + Ok(Line::from_content(line_type, current_line, coalition_ids)?) + } + LineType::Unknown => Err(ProcessingError::UnknownLineType), } } @@ -57,11 +73,11 @@ impl Line { line_type: LineType, current_line: &'a S, coalition_ids: &mut CoalitionIDs<'a>, - ) -> Self { - let id = Self::get_id_from_line(current_line); + ) -> Result { + let id = Self::get_id_from_line(current_line)?; let continued = Self::will_line_continue(current_line); let coalition = Self::assign_id_to_coalitions(coalition_ids, current_line, id); - Line::new(line_type, continued, coalition) + Ok(Line::new(line_type, continued, coalition)) } fn assign_id_to_coalitions<'a, S: AsRef>( @@ -82,8 +98,12 @@ impl Line { current_line.as_ref().ends_with('\\') } - fn get_id_from_line>(line: &S) -> &str { - line.as_ref().split_once(',').unwrap().0 + fn get_id_from_line>(line: &S) -> Result<&str, ProcessingError> { + Ok(line + .as_ref() + .split_once(',') + .ok_or(ProcessingError::CannotGetIDFromLine)? + .0) } fn new(line_type: LineType, continued: bool, coalition: Coalition) -> Self { @@ -93,7 +113,9 @@ impl Line { coalition, } } +} +impl Default for Line { fn default() -> Self { Self::new(LineType::Unknown, false, Coalition::Unknown) } @@ -108,14 +130,41 @@ enum LineType { } impl LineType { - fn find_type>(line: &S) -> Self { - let first_char = line.as_ref().chars().next().unwrap(); + fn find_type>(line: &S) -> Result { + let first_char = line + .as_ref() + .chars() + .next() + .ok_or(ProcessingError::LineIsEmptyError)?; if first_char == COMMENT { - Self::Timestamp + Ok(Self::Timestamp) } else if first_char == MINUS { - Self::Destruction + Ok(Self::Destruction) } else { - LineType::Telemetry + Ok(LineType::Telemetry) + } + } +} + +#[derive(Debug)] +enum ProcessingError { + LineIsEmptyError, + UnknownLineType, + CannotSplitIntoHeaderAndBody, + CannotGetIDFromLine, +} + +impl Error for ProcessingError {} + +impl Display for ProcessingError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::LineIsEmptyError => write!(f, "line in tacview file is empty"), + Self::UnknownLineType => write!(f, "unknown line type in tacview file"), + Self::CannotSplitIntoHeaderAndBody => { + write!(f, "cannot split the file into header and body") + } + Self::CannotGetIDFromLine => write!(f, "cannot get unit ID from line"), } } } diff --git a/src/reader.rs b/src/reader.rs index 46b8227..5f26aa0 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -38,7 +38,10 @@ fn read_zip(buf: BufReader) -> Result, Error> { Ok(read_txt(inner_buf)?) } -fn read_txt(buf: T) -> Result, Error> { - let lines: Vec = buf.lines().map(|l|).collect(); +fn read_txt(buf: impl BufRead) -> Result, Error> { + let lines: Vec = buf + .lines() + .map(|l| l.expect("Could not read from the file")) + .collect(); Ok(lines) }