use crate::config::Config;
use colored::*;
const INFO_INDENT: &str = " ";
pub enum Info {
Available(String),
NotAvailable,
Other,
}
pub struct Pass<'a, T>(&'a str, &'a dyn Fn(&T) -> Vec<(&'a str, Info)>);
impl<'a, T> Pass<'a, T> {
fn name(&self) -> &'a str {
&self.0
}
fn run(&self, input: &T) -> Vec<(&'a str, Info)> {
(self.1)(input)
}
}
pub trait PassSequence<'a> {
type T: 'a;
const TY_NAME: &'static str;
const PASSES: &'a [Pass<'a, Self::T>];
fn run(input: &Self::T, config: &Config) -> Vec<(&'a str, Result<Vec<(&'a str, Info)>, ()>)> {
let mut results = Vec::new();
for pass in Self::PASSES {
results.push((
pass.name(),
if !config.is_ignored(&pass.name()) {
Ok(pass.run(input))
} else {
Err(())
},
));
}
results
}
}
pub fn run<'a, S>(input: &S::T, config: &Config)
where
S: PassSequence<'a>,
S::T: ToString + 'a,
{
let data = input.to_string().red().bold();
let ty = S::TY_NAME.yellow().bold();
println!("found {}({})", ty, data);
for (name, result) in S::run(input, config) {
println!(
"{} {} {}",
match result {
Ok(_) => "➔",
Err(_) => "✘",
},
name.magenta().bold(),
match result {
Ok(_) => "",
Err(_) => "ignored",
},
);
if let Ok(result) = result {
for (name, info) in result {
println!(
"{}{} {}",
INFO_INDENT,
name.to_string().blue().bold(),
match info {
Info::Available(value) => value.to_string().green().bold(),
Info::NotAvailable => "n/a".cyan().bold(),
Info::Other => "other".cyan().bold(),
}
);
}
}
}
}
macro_rules! push {
($result:ident, $name:expr, n / a) => {
$result.push(($name, $crate::passes::Info::NotAvailable))
};
($result:ident, $name:expr, other) => {
$result.push(($name, $crate::passes::Info::Other))
};
($result:ident, $name:expr, $value:expr) => {
$result.push(($name, $crate::passes::Info::Available($value.to_string())))
};
}
macro_rules! pass_sequence {
($($id:expr),*) => {
&[$($crate::passes::Pass(stringify!($id), &$id)),*]
}
}
pub mod integer;
pub mod ip_addr;
pub mod string;