cyfs_util/util/
toml_helper.rs

1use cyfs_base::{BuckyError, BuckyErrorCode, BuckyResult};
2use std::str::FromStr;
3use std::convert::TryFrom;
4
5
6pub struct TomlHelper;
7impl TomlHelper {
8    pub fn decode_from_string<T>(v: &toml::Value) -> BuckyResult<T>
9    where
10        T: FromStr,
11        <T as FromStr>::Err: std::fmt::Display,
12    {
13        if !v.is_str() {
14            let msg = format!("invalid toml field, except string: {}", v);
15            warn!("{}", msg);
16
17            return Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg));
18        }
19
20        let v = T::from_str(v.as_str().unwrap()).map_err(|e| {
21            let msg = format!(
22                "parse toml string error: value={}, {}",
23                v.as_str().unwrap(),
24                e
25            );
26            warn!("{}", msg);
27
28            BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
29        })?;
30
31        Ok(v)
32    }
33
34    pub fn decode_from_boolean(v: &toml::Value) -> BuckyResult<bool> {
35        let v = v.as_bool().ok_or_else(|| {
36            let msg = format!("invalid toml field, except bool: {}", v);
37            warn!("{}", msg);
38
39            BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
40        })?;
41
42        Ok(v)
43    }
44
45    pub fn decode_string_field<T>(obj: &toml::value::Table, key: &str) -> BuckyResult<T>
46    where
47        T: FromStr,
48        <T as FromStr>::Err: std::fmt::Display,
49    {
50        let v = obj.get(key).ok_or_else(|| {
51            let msg = format!("field not found: {}", key);
52            warn!("{}", msg);
53
54            BuckyError::new(BuckyErrorCode::NotFound, msg)
55        })?;
56
57        Self::decode_from_string(v)
58    }
59
60    pub fn decode_option_string_field<T>(
61        obj: &toml::value::Table,
62        key: &str,
63    ) -> BuckyResult<Option<T>>
64    where
65        T: FromStr,
66        <T as FromStr>::Err: std::fmt::Display,
67    {
68        match obj.get(key) {
69            Some(v) => {
70                let obj = Self::decode_from_string(v)?;
71                Ok(Some(obj))
72            }
73            None => Ok(None),
74        }
75    }
76
77    pub fn decode_to_int<T>(v: &toml::Value) -> BuckyResult<T>
78    where
79        T: FromStr + TryFrom<u64> + TryFrom<i64>,
80        <T as FromStr>::Err: std::fmt::Display,
81        <T as TryFrom<u64>>::Error: std::fmt::Display,
82        <T as TryFrom<i64>>::Error: std::fmt::Display,
83    {
84        if v.is_str() {
85            let v = T::from_str(v.as_str().unwrap()).map_err(|e| {
86                let msg = format!(
87                    "parse toml string to int error: value={}, {}",
88                    v.as_str().unwrap(),
89                    e
90                );
91                warn!("{}", msg);
92                BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
93            })?;
94
95            Ok(v)
96        } else if v.is_integer() {
97            if v.is_integer() {
98                let v = T::try_from(v.as_integer().unwrap()).map_err(|e| {
99                    let msg = format!(
100                        "parse toml integer to int error: value={}, {}",
101                        v.as_integer().unwrap(),
102                        e
103                    );
104                    warn!("{}", msg);
105                    BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
106                })?;
107                Ok(v)
108            } else {
109                let msg = format!(
110                    "parse toml integer to int error: value={}",
111                    v.as_integer().unwrap(),
112                );
113                warn!("{}", msg);
114                Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg))
115            }
116        } else {
117            let msg = format!("invalid toml field, except string or integer: {}", v);
118            warn!("{}", msg);
119
120            Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg))
121        }
122    }
123
124
125    pub fn extract_sub_node(mut root: toml::Value, path: &str) -> BuckyResult<toml::Value> {
126        let parts: Vec<&str> = path.split('.').collect();
127
128        for part in parts {
129            root = Self::extract_node(root, part)?;
130        }
131
132        Ok(root)
133    }
134
135    pub fn extract_node(root: toml::Value, name: &str) -> BuckyResult<toml::Value> {
136        match root {
137            toml::Value::Table(mut cfg) => match cfg.remove(name) {
138                Some(v) => Ok(v),
139                None => {
140                    let msg = format!("sub node not found! name={}", name);
141                    error!("{}", msg);
142                    Err(BuckyError::new(BuckyErrorCode::NotFound, msg))
143                }
144            }
145
146            _ => {
147                let msg = format!(
148                    "node is not table! config={}", toml::to_string(&root).unwrap()
149                );
150                error!("{}", msg);
151                Err(BuckyError::from((BuckyErrorCode::InvalidFormat, msg)))
152            }
153        }
154    }
155}