summaryrefslogtreecommitdiffstats
path: root/src/source.rs
blob: bb3efd6ba631b8562181109d47b38aed4af5bc71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::fs;
use std::env;
use std::error::Error;
use std::io::Read;
use std::collections::HashMap;

use toml;

use value::Value;

pub trait Source {
    fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>>;
}

#[derive(Default)]
pub struct File {
    // Basename of configuration file
    name: String,

    // Namespace to restrict configuration from the file
    namespace: Option<String>,

    // A required File will error if it cannot be found
    required: bool,
}

impl File {
    pub fn with_name(name: &str) -> File {
        File {
            name: name.into(),
            required: true,

            ..Default::default()
        }
    }

    pub fn namespace(&mut self, namespace: &str) -> &mut File {
        self.namespace = Some(namespace.into());
        self
    }

    pub fn required(&mut self, required: bool) -> &mut File {
        self.required = required;
        self
    }
}

fn collect(content: &mut HashMap<String, Value>, table: &toml::Table, prefix: Option<String>) {
    for (key, value) in table {
        // Construct full key from prefix
        let key = if let Some(ref prefix) = prefix {
            prefix.clone() + "." + key
        } else {
            key.clone()
        };

        match *value {
            // Recurse into nested table
            toml::Value::Table(ref table) => collect(content, table, Some(key)),

            toml::Value::String(ref value) => {
                content.insert(key, value.clone().into());
            }

            _ => {
                // Unhandled
            }
        }
    }
}

impl Source for File {
    fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>> {
        // Find file
        // TODO: Use a nearest algorithm rather than strictly CWD
        let cwd = env::current_dir()?;
        let filename = cwd.join(self.name.clone() + ".toml");

        // Read contents from file
        let mut file = fs::File::open(filename)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;

        // Parse
        let mut parser = toml::Parser::new(&buffer);
        // TODO: Get a solution to make this return an Error-able
        let document = parser.parse().unwrap();

        // Iterate through document and fill content
        let mut content = HashMap::new();
        collect(&mut content, &document, None);

        Ok(content)
    }
}