use crate::util::*;
#[derive(Debug, Default)]
pub struct ErrPrinter<'a> {
max_errors: Option<u32>,
error_code_filter: Option<&'a [String]>,
}
impl<'a> ErrPrinter<'a> {
pub fn new(max_errors: Option<u32>, error_code_filter: Option<&'a [String]>) -> Self {
Self {
max_errors,
error_code_filter,
}
}
pub fn print<E: Iterator<Item = &'a Box<str>>>(
&self,
err_msgs: E,
unique_error_codes: &[String],
) {
match self.error_code_filter {
Some(filter) => {
let min_filter = self.minify_filter(filter, unique_error_codes);
self.filter_error_msgs(self.max_errors, &min_filter, err_msgs)
.for_each(|e| crate::display_error(e));
}
None => {
err_msgs
.take(self.max_errors.unwrap_or(u32::MAX) as usize)
.for_each(|e| crate::display_error(e));
}
};
}
fn minify_filter(
&self,
error_code_filter: &[String],
unique_error_codes: &[String],
) -> Vec<String> {
error_code_filter
.iter()
.filter(|ec| unique_error_codes.contains(ec))
.map_into()
.collect::<Vec<String>>()
}
fn filter_error_msgs<'b, E: Iterator<Item = &'a Box<str>> + 'b>(
&self,
max_errors: Option<u32>,
ec_filter: &'b [String],
err_msgs: E,
) -> impl Iterator<Item = &'a Box<str>> + 'b {
err_msgs
.filter(move |err_msg| {
for ec in ec_filter {
let mut msg_chars = err_msg.chars();
if msg_chars
.position(|c| c == '[')
.map_or(false, |pos_err_code| {
match_error_code(err_msg, ec.chars(), msg_chars, pos_err_code)
})
{
return true;
}
}
false
})
.take(max_errors.unwrap_or(u32::MAX) as usize)
}
}
fn match_error_code(
err_msg: &str,
filter_chars: Chars,
err_msg_chars: Chars,
pos_err_code: usize,
) -> bool {
let mut pos_char_cmp: usize = pos_err_code;
debug_assert_eq!(&err_msg_chars.as_str()[0..=0], "E");
let msg_chars = err_msg_chars.skip(1);
pos_char_cmp += 1;
filter_chars
.zip(msg_chars)
.all(|(fchar, mchar)| {
pos_char_cmp += 1;
fchar == mchar
})
.then(|| {
pos_char_cmp += 1;
err_msg
.chars()
.nth(pos_char_cmp)
.map_or(false, |c| c == ']')
})
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_minify_filter() {
let err_code_filter = vec!["1".into(), "2".into(), "3".into(), "4".into(), "5".into()];
let err_printer = ErrPrinter::new(None, Some(&err_code_filter));
let unique_error_codes: Vec<String> = vec!["1".into(), "5".into(), "6".into(), "7".into()];
let minified_filter = err_printer.minify_filter(&err_code_filter, &unique_error_codes);
assert_eq!(minified_filter, vec!["1", "5"]);
}
#[test]
fn test_minify_filter_narrow_unique_errors() {
let err_code_filter = vec![
"1".into(),
"200".into(),
"3".into(),
"004".into(),
"51".into(),
];
let err_printer = ErrPrinter::new(None, Some(&err_code_filter));
let unique_error_codes: Vec<String> = vec![
"01".into(),
"20".into(),
"6".into(),
"10".into(),
"51".into(),
"04".into(),
"30".into(),
];
let minified_filter = err_printer.minify_filter(&err_code_filter, &unique_error_codes);
assert_eq!(minified_filter, vec!["51"]);
}
#[test]
fn test_minify_filter_wide_unique_error_codes() {
let err_code_filter = vec![
"01".into(),
"20".into(),
"6".into(),
"10".into(),
"51".into(),
"04".into(),
"30".into(),
];
let err_printer = ErrPrinter::new(None, Some(&err_code_filter));
let unique_error_codes: Vec<String> = vec![
"1".into(),
"200".into(),
"3".into(),
"004".into(),
"51".into(),
"100".into(),
];
let minified_filter = err_printer.minify_filter(&err_code_filter, &unique_error_codes);
assert_eq!(minified_filter, vec!["51"]);
}
#[test]
fn test_filter_error_messages_simple() {
let err_code_filter = vec!["1".into()];
let err_printer = ErrPrinter::new(None, Some(&err_code_filter));
let err_msgs = [
"Error message [E1] 1st of should be filtered".into(),
"Error message [E2]".into(),
"Error message [E1] 2nd of should be filtered".into(),
"Error message [E4]".into(),
];
let filtered_err_msgs: Vec<&Box<str>> = err_printer
.filter_error_msgs(None, &err_code_filter, err_msgs.iter())
.collect();
assert_eq!(
filtered_err_msgs,
[
&"Error message [E1] 1st of should be filtered".into(),
&"Error message [E1] 2nd of should be filtered".into(),
]
);
}
#[test]
fn test_filter_error_messages() {
let err_code_filter = vec!["1".into(), "2".into(), "3".into(), "4".into(), "5".into()];
let err_printer = ErrPrinter::new(None, Some(&err_code_filter));
let err_msgs = [
"Error message [E1]".into(),
"Error message [E2]".into(),
"Error message [E3]".into(),
"Error message [E4]".into(),
"Error message [E5]".into(),
"Error message [E6]".into(),
"Error message [E2]".into(),
"Error message [E7]".into(),
"Error message [E8]".into(),
"Error message [E9]".into(),
"Error message [E01]".into(),
"Error message [E100]".into(),
];
let filtered_err_msgs: Vec<&Box<str>> = err_printer
.filter_error_msgs(None, &err_code_filter, err_msgs.iter())
.collect();
assert_eq!(
filtered_err_msgs,
vec![
&"Error message [E1]".into(),
&"Error message [E2]".into(),
&"Error message [E3]".into(),
&"Error message [E4]".into(),
&"Error message [E5]".into(),
&"Error message [E2]".into(),
]
);
}
}