more error handling

This commit is contained in:
132nd-Professor
2022-08-12 16:19:42 +02:00
parent 7d66b1ff31
commit b82c40d4ab
3 changed files with 77 additions and 25 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ fn main() {
fn main_inner() -> Result<(), Box<dyn std::error::Error>> { fn main_inner() -> Result<(), Box<dyn std::error::Error>> {
let (input_filename, is_zip) = reader::find_input_file()?; let (input_filename, is_zip) = reader::find_input_file()?;
println!("Processing {}", input_filename); 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 (header, body) = processor::split_into_header_and_body(&lines);
let coalition_per_line = processor::divide_body_by_coalition(body); let coalition_per_line = processor::divide_body_by_coalition(body);
+71 -22
View File
@@ -1,31 +1,45 @@
use std::error::Error;
use std::fmt::Display;
use std::hash::Hash; use std::hash::Hash;
use crate::constants::{COMMENT, MINUS}; use crate::constants::{COMMENT, MINUS};
use crate::tacview::{Coalition, CoalitionIDs}; use crate::tacview::{Coalition, CoalitionIDs};
pub fn split_into_header_and_body<S: AsRef<str>>(lines: &[S]) -> (&[S], &[S]) { pub fn split_into_header_and_body<S, E>(lines: &[S]) -> Result<(&[S], &[S]), ProcessingError>
where
S: AsRef<str>,
{
let mut i = 0; let mut i = 0;
for line in lines { 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; break;
} }
i += 1; i += 1;
} }
(&lines[..i], &lines[i..]) Ok((&lines[..i], &lines[i..]))
} }
pub fn divide_body_by_coalition<S: AsRef<str> + Hash + Eq>(body: &[S]) -> Vec<Coalition> { pub fn divide_body_by_coalition<S>(body: &[S]) -> Result<Vec<Coalition>, Box<dyn Error>>
where
S: AsRef<str> + Hash + Eq,
{
let mut result = vec![]; let mut result = vec![];
let mut coalition_ids: CoalitionIDs = CoalitionIDs::new(); let mut coalition_ids: CoalitionIDs = CoalitionIDs::new();
let mut old_line = Line::default(); let mut old_line = Line::default();
for line_s in body { 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()); result.push(processed.coalition.clone());
old_line = processed; old_line = processed;
} }
result Ok(result)
} }
struct Line { struct Line {
@@ -39,17 +53,19 @@ impl Line {
old_line: Line, old_line: Line,
current_line: &'a S, current_line: &'a S,
coalition_ids: &mut CoalitionIDs<'a>, coalition_ids: &mut CoalitionIDs<'a>,
) -> Self { ) -> Result<Self, ProcessingError> {
let line_type = match old_line.continued { let line_type = match old_line.continued {
true => old_line.line_type, true => old_line.line_type,
false => LineType::find_type(current_line), false => LineType::find_type(current_line)?,
}; };
match line_type { match line_type {
LineType::Telemetry => Line::from_content(line_type, current_line, coalition_ids), LineType::Telemetry => Ok(Line::from_content(line_type, current_line, coalition_ids)?),
LineType::Timestamp => Line::new(line_type, false, Coalition::All), LineType::Timestamp => Ok(Line::new(line_type, false, Coalition::All)),
LineType::Destruction => Line::from_content(line_type, current_line, coalition_ids), LineType::Destruction => {
LineType::Unknown => panic!(""), Ok(Line::from_content(line_type, current_line, coalition_ids)?)
}
LineType::Unknown => Err(ProcessingError::UnknownLineType),
} }
} }
@@ -57,11 +73,11 @@ impl Line {
line_type: LineType, line_type: LineType,
current_line: &'a S, current_line: &'a S,
coalition_ids: &mut CoalitionIDs<'a>, coalition_ids: &mut CoalitionIDs<'a>,
) -> Self { ) -> Result<Self, ProcessingError> {
let id = Self::get_id_from_line(current_line); let id = Self::get_id_from_line(current_line)?;
let continued = Self::will_line_continue(current_line); let continued = Self::will_line_continue(current_line);
let coalition = Self::assign_id_to_coalitions(coalition_ids, current_line, id); 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<str>>( fn assign_id_to_coalitions<'a, S: AsRef<str>>(
@@ -82,8 +98,12 @@ impl Line {
current_line.as_ref().ends_with('\\') current_line.as_ref().ends_with('\\')
} }
fn get_id_from_line<S: AsRef<str>>(line: &S) -> &str { fn get_id_from_line<S: AsRef<str>>(line: &S) -> Result<&str, ProcessingError> {
line.as_ref().split_once(',').unwrap().0 Ok(line
.as_ref()
.split_once(',')
.ok_or(ProcessingError::CannotGetIDFromLine)?
.0)
} }
fn new(line_type: LineType, continued: bool, coalition: Coalition) -> Self { fn new(line_type: LineType, continued: bool, coalition: Coalition) -> Self {
@@ -93,7 +113,9 @@ impl Line {
coalition, coalition,
} }
} }
}
impl Default for Line {
fn default() -> Self { fn default() -> Self {
Self::new(LineType::Unknown, false, Coalition::Unknown) Self::new(LineType::Unknown, false, Coalition::Unknown)
} }
@@ -108,14 +130,41 @@ enum LineType {
} }
impl LineType { impl LineType {
fn find_type<S: AsRef<str>>(line: &S) -> Self { fn find_type<S: AsRef<str>>(line: &S) -> Result<Self, ProcessingError> {
let first_char = line.as_ref().chars().next().unwrap(); let first_char = line
.as_ref()
.chars()
.next()
.ok_or(ProcessingError::LineIsEmptyError)?;
if first_char == COMMENT { if first_char == COMMENT {
Self::Timestamp Ok(Self::Timestamp)
} else if first_char == MINUS { } else if first_char == MINUS {
Self::Destruction Ok(Self::Destruction)
} else { } 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"),
} }
} }
} }
+5 -2
View File
@@ -38,7 +38,10 @@ fn read_zip(buf: BufReader<File>) -> Result<Vec<String>, Error> {
Ok(read_txt(inner_buf)?) Ok(read_txt(inner_buf)?)
} }
fn read_txt<T: BufRead>(buf: T) -> Result<Vec<String>, Error> { fn read_txt(buf: impl BufRead) -> Result<Vec<String>, Error> {
let lines: Vec<String> = buf.lines().map(|l|).collect(); let lines: Vec<String> = buf
.lines()
.map(|l| l.expect("Could not read from the file"))
.collect();
Ok(lines) Ok(lines)
} }