1use std::{fs, path};
2
3use crate::v5;
4use crate::{Error, ErrorKind, Result};
5
6#[macro_export]
7macro_rules! config_field {
8 ($table:ident, $field:ident, $config:ident, $($args:tt)+) => {{
9 let field = stringify!($field);
10 if let Some(val) = $table.get(field) {
11 $config.$field = match val.$($args)+ {
12 Some(val) => val.parse()?,
13 None => err!(
14 InvalidInput,
15 desc: "invalid config field {}, {}", field, val.to_string()
16 )?,
17 }
18 }
19 }};
20 (opt: $table:ident, $field:ident, $config:ident, $($args:tt)+) => {{
21 let field = stringify!($field);
22 if let Some(val) = $table.get(field) {
23 $config.$field = match val.$($args)+ {
24 Some(val) => Some(val.parse()?),
25 None => err!(
26 InvalidInput,
27 desc: "invalid config field {}, {}", field, val.to_string()
28 )?,
29 }
30 }
31 }};
32}
33
34#[derive(Clone, Eq, PartialEq)]
36pub struct Config {
37 #[cfg(feature = "broker")]
39 pub broker: crate::broker::Config,
40
41 pub mqtt_v5: v5::Config,
43}
44
45impl Default for Config {
46 fn default() -> Config {
47 Config {
48 #[cfg(feature = "broker")]
49 broker: crate::broker::Config::default(),
50 mqtt_v5: v5::Config::default(),
51 }
52 }
53}
54
55impl TryFrom<toml::Value> for Config {
56 type Error = Error;
57
58 fn try_from(val: toml::Value) -> Result<Config> {
59 let config = match val.as_table() {
60 Some(map) => Config {
61 #[cfg(feature = "broker")]
62 broker: match map.get("broker") {
63 Some(value) => crate::broker::Config::try_from(value.clone())?,
64 None => crate::broker::Config::default(),
65 },
66 mqtt_v5: match map.get("mqtt_v5") {
67 Some(value) => v5::Config::try_from(value.clone())?,
68 None => v5::Config::default(),
69 },
70 },
71 None => err!(InvalidInput, desc: "invalid toml configuration")?,
72 };
73 Ok(config)
74 }
75}
76
77impl Config {
78 pub fn from_file<P>(loc: P) -> Result<Config>
80 where
81 P: AsRef<path::Path>,
82 {
83 use std::str::from_utf8;
84
85 let ploc: &path::Path = loc.as_ref();
86
87 let value: toml::Value = {
88 let data = err!(IOError, try: fs::read(ploc), "reading config {:?}", ploc)?;
89 let txt = err!(InvalidInput, try: from_utf8(&data), "bad config {:?}", ploc)?;
90 err!(InvalidInput, try: toml::from_str(txt), "config not toml {:?}", ploc)?
91 };
92
93 Config::try_from(value)
94 }
95
96 pub fn validate(&self) -> Result<()> {
98 #[cfg(feature = "broker")]
99 self.broker.validate()?;
100
101 self.mqtt_v5.validate()?;
102 Ok(())
103 }
104}