use std::{
collections::HashSet,
env,
hash::Hash,
process::{Child, Command},
};
use rand::{
distr::{Alphanumeric, Uniform},
rng, RngExt as _,
};
use crate::Result;
pub fn is_unique<T>(iter: T) -> bool
where
T: IntoIterator,
T::Item: Eq + Hash,
{
let mut uniq = HashSet::new();
iter.into_iter().all(move |x| uniq.insert(x))
}
pub fn is_default<T: Default + PartialEq>(t: &T) -> bool {
*t == Default::default()
}
pub fn rand_string(n: usize) -> String {
rng()
.sample_iter(&Alphanumeric)
.take(n)
.map(char::from)
.collect()
}
pub fn rand_string_hex(n: usize) -> String {
let mut rng = rng();
let bytes: Vec<u8> = (0..n.div_ceil(2)).map(|_| rng.random()).collect();
let mut s = hex::encode(bytes);
s.truncate(n);
s
}
pub fn rand_string_all(n: usize) -> String {
rng()
.sample_iter(Uniform::new(char::from(33), char::from(127)).unwrap())
.take(n)
.collect()
}
pub fn restart() -> Result<Child> {
Command::new(env::current_exe()?)
.args(env::args().skip(1))
.spawn()
.map_err(Into::into)
}
#[cfg(feature = "rustls")]
pub fn load_rustls_config<P: AsRef<std::path::Path>>(
cert: P,
key: P,
) -> Result<rustls::ServerConfig> {
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let config = rustls::ServerConfig::builder().with_no_client_auth();
let cert_chain =
rustls_pemfile::certs(&mut std::io::BufReader::new(std::fs::File::open(cert)?))
.collect::<Result<Vec<_>, _>>()?;
let mut key_chain =
rustls_pemfile::pkcs8_private_keys(&mut std::io::BufReader::new(std::fs::File::open(key)?))
.map(|v| v.map(rustls::pki_types::PrivateKeyDer::Pkcs8))
.collect::<Result<Vec<_>, _>>()?;
let Some(private_key) = key_chain.pop() else {
anyhow::bail!("Cannot find PKCS 8 private key");
};
config
.with_single_cert(cert_chain, private_key)
.map_err(Into::into)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_unique() {
assert!(is_unique(vec![1, 2, 3]));
assert!(is_unique([1, 2, 3]));
assert!(is_unique(vec![1]));
assert!(is_unique(Vec::<i32>::new()));
assert!(!is_unique(vec![1, 2, 2]));
assert!(!is_unique([1, 1]));
assert!(is_unique("abc".chars()));
assert!(!is_unique("aba".chars()));
assert!(is_unique("".chars()));
}
#[test]
fn test_is_default() {
assert!(is_default(&0_u8));
assert!(is_default(&0_i64));
assert!(!is_default(&1_i64));
assert!(is_default(&String::new()));
assert!(!is_default(&"a".to_string()));
assert!(is_default(&Vec::<i32>::new()));
assert!(!is_default(&vec![1]));
assert!(is_default(&Option::<i32>::None));
assert!(!is_default(&Some(1)));
}
#[test]
fn test_rand_string() {
for n in [0, 1, 2, 3, 4, 5, 10, 63, 64] {
let s = rand_string(n);
assert_eq!(s.len(), n);
assert!(s.chars().all(|c| c.is_ascii_alphanumeric()));
}
}
#[test]
fn test_rand_string_hex() {
for n in [0, 1, 2, 3, 4, 5, 10, 63, 64] {
let s = rand_string_hex(n);
assert_eq!(s.len(), n);
assert!(s.bytes().all(|b| b.is_ascii_hexdigit()));
}
}
#[test]
fn test_rand_string_all() {
let s = rand_string_all(4000);
assert!(s.chars().all(|c| ('!'..='~').contains(&c)),);
}
}