pub mod file_utils;
use crate::Result;
use std::collections::HashSet;
use std::ffi::OsStr;
use std::iter::FromIterator;
pub fn validate_input_list<'a, S, T, U>(
input: T,
allowed_values: Option<U>,
allow_duplicates: bool,
duplicate_error_customizer: Option<&dyn Fn(&S, usize, usize) -> String>,
value_error_customizer: Option<&dyn Fn(&Vec<&&S>) -> String>,
) -> Result<()>
where
S: 'a + std::cmp::Eq + std::hash::Hash + std::fmt::Display,
T: IntoIterator<Item = &'a S>,
U: IntoIterator<Item = &'a S>,
{
let input_vector: Vec<&S> = input.into_iter().collect();
let mut input_hash: HashSet<&S> = HashSet::new();
for (idx, i) in input_vector.iter().enumerate() {
let added = input_hash.insert(i);
if !allow_duplicates & !added {
let f_idx = input_vector
.iter()
.position(|x| x == i)
.expect(&format!("Expected element {} in input", i.to_string()));
if let Some(f) = duplicate_error_customizer {
bail!(&f(i, f_idx, idx));
} else {
bail!(
"Input contains duplicate value '{}' at index {}, which is not allowed in the this context (first occurrence at index {})",
i.to_string(),
idx,
f_idx
);
}
}
}
if let Some(allowed) = allowed_values {
let hash_allowed = HashSet::from_iter(allowed.into_iter());
let diff: Vec<&&S> = input_hash.difference(&hash_allowed).into_iter().collect();
if diff.len() > 0 {
if let Some(f) = value_error_customizer {
bail!(&f(&diff));
} else {
bail!(
"Input contains values which are not allowed in this context: {}",
diff.iter()
.map(|d| format!("'{}'", d))
.collect::<Vec<String>>()
.join(", ")
);
}
}
}
Ok(())
}
pub fn str_to_bool(s: &str) -> Result<bool> {
match s {
"true" | "True" => Ok(true),
"false" | "False" => Ok(false),
_ => bail!("Could not convert string {} to boolean value", s),
}
}
pub fn str_from_byte_array(bytes: &[u8]) -> Result<String> {
let mut s = String::new();
for b in bytes {
s.push_str(&format!("{:02x}", b));
}
Ok(s)
}
pub fn resolve_os_str(s: &OsStr) -> Result<String> {
Ok(s.to_os_string().into_string()?)
}
pub fn bytes_from_str_of_bytes(s: &str) -> Result<Vec<u8>> {
let mut bytes = vec![];
for chrs in s.chars().collect::<Vec<char>>().chunks(2) {
let s = format!("{}{}", chrs[0], chrs[1]);
bytes.push(
u8::from_str_radix(&s, 16)
.expect(&format!("Could not interpret byte {} as a hex value", s)),
);
}
Ok(bytes)
}
pub fn unsorted_dedup<T: Eq + std::hash::Hash + Clone>(v: &mut Vec<T>) {
let mut uniques = std::collections::HashSet::new();
v.retain(|e| uniques.insert(e.clone()));
}