Skip to main content

actix_cloud/
utils.rs

1use std::{
2    collections::HashSet,
3    env,
4    hash::Hash,
5    process::{Child, Command},
6};
7
8use rand::{
9    distr::{Alphanumeric, Uniform},
10    rng, RngExt as _,
11};
12
13use crate::Result;
14
15/// Check whether iterator `iter` contains only unique values.
16pub fn is_unique<T>(iter: T) -> bool
17where
18    T: IntoIterator,
19    T::Item: Eq + Hash,
20{
21    let mut uniq = HashSet::new();
22    iter.into_iter().all(move |x| uniq.insert(x))
23}
24
25/// Check whether `t` type `T` is equal to default.
26pub fn is_default<T: Default + PartialEq>(t: &T) -> bool {
27    *t == Default::default()
28}
29
30/// Get `n` bytes random string.
31/// `[a-zA-Z0-9]+`
32pub fn rand_string(n: usize) -> String {
33    rng()
34        .sample_iter(&Alphanumeric)
35        .take(n)
36        .map(char::from)
37        .collect()
38}
39
40/// Get `n` bytes random hex string.
41/// `[a-f0-9]+`
42pub fn rand_string_hex(n: usize) -> String {
43    let mut rng = rng();
44    let bytes: Vec<u8> = (0..n.div_ceil(2)).map(|_| rng.random()).collect();
45    let mut s = hex::encode(bytes);
46    s.truncate(n);
47    s
48}
49
50/// Get `n` bytes random string (all printable ascii).
51pub fn rand_string_all(n: usize) -> String {
52    rng()
53        .sample_iter(Uniform::new(char::from(33), char::from(127)).unwrap())
54        .take(n)
55        .collect()
56}
57
58/// Restart the program and keep the argument.
59///
60/// Inherit the environment/io/working directory of current process.
61pub fn restart() -> Result<Child> {
62    Command::new(env::current_exe()?)
63        .args(env::args().skip(1))
64        .spawn()
65        .map_err(Into::into)
66}
67
68#[cfg(feature = "rustls")]
69/// Load SSL certificate and key.
70pub fn load_rustls_config<P: AsRef<std::path::Path>>(
71    cert: P,
72    key: P,
73) -> Result<rustls::ServerConfig> {
74    let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
75    let config = rustls::ServerConfig::builder().with_no_client_auth();
76    let cert_chain =
77        rustls_pemfile::certs(&mut std::io::BufReader::new(std::fs::File::open(cert)?))
78            .collect::<Result<Vec<_>, _>>()?;
79    let mut key_chain =
80        rustls_pemfile::pkcs8_private_keys(&mut std::io::BufReader::new(std::fs::File::open(key)?))
81            .map(|v| v.map(rustls::pki_types::PrivateKeyDer::Pkcs8))
82            .collect::<Result<Vec<_>, _>>()?;
83
84    let Some(private_key) = key_chain.pop() else {
85        anyhow::bail!("Cannot find PKCS 8 private key");
86    };
87
88    config
89        .with_single_cert(cert_chain, private_key)
90        .map_err(Into::into)
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_is_unique() {
99        assert!(is_unique(vec![1, 2, 3]));
100        assert!(is_unique([1, 2, 3]));
101        assert!(is_unique(vec![1]));
102        assert!(is_unique(Vec::<i32>::new()));
103        assert!(!is_unique(vec![1, 2, 2]));
104        assert!(!is_unique([1, 1]));
105        assert!(is_unique("abc".chars()));
106        assert!(!is_unique("aba".chars()));
107        assert!(is_unique("".chars()));
108    }
109
110    #[test]
111    fn test_is_default() {
112        assert!(is_default(&0_u8));
113        assert!(is_default(&0_i64));
114        assert!(!is_default(&1_i64));
115        assert!(is_default(&String::new()));
116        assert!(!is_default(&"a".to_string()));
117        assert!(is_default(&Vec::<i32>::new()));
118        assert!(!is_default(&vec![1]));
119        assert!(is_default(&Option::<i32>::None));
120        assert!(!is_default(&Some(1)));
121    }
122
123    #[test]
124    fn test_rand_string() {
125        for n in [0, 1, 2, 3, 4, 5, 10, 63, 64] {
126            let s = rand_string(n);
127            assert_eq!(s.len(), n);
128            assert!(s.chars().all(|c| c.is_ascii_alphanumeric()));
129        }
130    }
131
132    #[test]
133    fn test_rand_string_hex() {
134        for n in [0, 1, 2, 3, 4, 5, 10, 63, 64] {
135            let s = rand_string_hex(n);
136            assert_eq!(s.len(), n);
137            assert!(s.bytes().all(|b| b.is_ascii_hexdigit()));
138        }
139    }
140
141    #[test]
142    fn test_rand_string_all() {
143        let s = rand_string_all(4000);
144        assert!(s.chars().all(|c| ('!'..='~').contains(&c)),);
145    }
146}