Skip to main content

clap_conf/
replace.rs

1//use failure_derive::*;
2use thiserror::*;
3
4#[derive(Clone, Error, Debug)]
5pub enum ConfError {
6    #[error("Syntax Error Parsing String")]
7    Syntax,
8    #[error("Environment variable not found")]
9    VarNotFound,
10    #[error("Could not load file {}", 0)]
11    LoadError(String),
12    #[error("{}", _0)]
13    Mess(&'static str),
14    #[error("{}", _0)]
15    Message(String),
16}
17
18impl ConfError {
19    pub fn with_info(self, s: &str) -> Self {
20        ConfError::Message(format!("{} - {}", self, s))
21    }
22}
23
24impl From<&'static str> for ConfError {
25    fn from(s: &'static str) -> Self {
26        ConfError::Mess(s)
27    }
28}
29
30impl From<std::io::Error> for ConfError {
31    fn from(e: std::io::Error) -> Self {
32        ConfError::LoadError(e.to_string())
33    }
34}
35
36impl From<std::env::VarError> for ConfError {
37    fn from(_: std::env::VarError) -> Self {
38        ConfError::VarNotFound
39    }
40}
41impl From<toml::de::Error> for ConfError {
42    fn from(_: toml::de::Error) -> Self {
43        ConfError::Syntax
44    }
45}
46
47type Job<E> = dyn Fn(&str) -> Result<String, E>;
48
49fn _replace<IT, E>(it: &mut IT, f: &Job<E>, depth: u8) -> Result<String, ConfError>
50where
51    IT: Iterator<Item = char>,
52    //J:Job<E>,
53    ConfError: From<E>,
54{
55    let mut res = String::new();
56    while let Some(c) = it.next() {
57        match c {
58            '\\' => res.push(it.next().ok_or(ConfError::Syntax)?),
59            '{' => {
60                let s = _replace(it, f, depth + 1)?;
61                res.push_str(&f(&s)?);
62            }
63            '}' => {
64                if depth == 0 {
65                    return Err(ConfError::Syntax);
66                }
67                return Ok(res);
68            }
69            c => res.push(c),
70        }
71    }
72    if depth > 0 {
73        return Err(ConfError::Syntax);
74    }
75    Ok(res)
76}
77
78pub fn replace<E>(s: &str, f: &Job<E>) -> Result<String, ConfError>
79where
80    ConfError: From<E>,
81    //J:Job<E>,
82{
83    _replace(&mut s.chars(), f, 0)
84}
85
86pub fn replace_simple<F: 'static + Fn(&str) -> String>(s: &str, f: F) -> Result<String, ConfError> {
87    replace::<ConfError>(s, &move |s| Ok(f(s)))
88}
89
90pub fn replace_env(s: &str) -> Result<String, ConfError> {
91    replace(s, &|v| std::env::var(v))
92}
93
94#[cfg(test)]
95mod test {
96    use super::*;
97    fn mini_rep(s: &str) -> String {
98        s.to_lowercase()
99    }
100    #[test]
101    pub fn rep_test() {
102        let s2 = replace_simple("HELLO{WORLD}", &mini_rep).unwrap();
103        assert_eq!(&s2, "HELLOworld");
104    }
105}