Skip to main content

config/
ini.rs

1use crate::{pascal_case, path, Error, FileSource, Result, Settings};
2use configparser::ini::Ini;
3use tokens::{ChangeToken, FileChangeToken, NeverChangeToken};
4
5/// Represents a [configuration provider](crate::Provider) for `*.ini` files.
6pub struct Provider(FileSource);
7
8impl Provider {
9    /// Initializes a new `*.ini` file configuration provider.
10    ///
11    /// # Arguments
12    ///
13    /// * `file` - The `*.ini` [file source](FileSource) information
14    #[inline]
15    pub fn new(file: FileSource) -> Self {
16        Self(file)
17    }
18}
19
20impl crate::Provider for Provider {
21    #[inline]
22    fn name(&self) -> &str {
23        path::provider(&self.0.path, "Ini")
24    }
25
26    fn reload_token(&self) -> Box<dyn ChangeToken> {
27        if self.0.reload_on_change {
28            Box::new(FileChangeToken::new(self.0.path.clone()))
29        } else {
30            Box::new(NeverChangeToken)
31        }
32    }
33
34    fn load(&self, settings: &mut Settings) -> Result {
35        if !self.0.path.is_file() {
36            if self.0.optional {
37                return Ok(());
38            } else {
39                return Err(Error::MissingFile(self.0.path.clone()));
40            }
41        }
42
43        let mut ini = Ini::new_cs();
44        let sections = ini.load(&self.0.path).map_err(Error::Custom)?;
45
46        for (section, pairs) in sections {
47            for (key, value) in pairs {
48                let key = format!("{}{}{}", pascal_case(&section), path::delimiter(), pascal_case(&key),);
49                settings.insert(key, value.unwrap_or_default());
50            }
51        }
52
53        Ok(())
54    }
55}