summaryrefslogtreecommitdiffstats
path: root/bin/core/imag-store/src/util.rs
blob: c1dcc8d390473c4938bcb3f180024694747d9ce2 (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::borrow::Cow;
use std::str::Split;

use clap::ArgMatches;
use toml::Value;
use toml::map::{Map, Entry};

use libimagutil::key_value_split::IntoKeyValue;

pub fn build_toml_header(matches: &ArgMatches, mut header: Value) -> Value {
    debug!("Building header from cli spec");
    if let Some(headerspecs) = matches.values_of("header") {
        let kvs = headerspecs
                            .filter_map(|hs| {
                                debug!("- Processing: '{}'", hs);
                                let kv = String::from(hs).into_kv();
                                debug!("-        got: '{:?}'", kv);
                                kv
                            });
        for tpl in kvs {
            let (key, value) = tpl.into();
            debug!("Splitting: {:?}", key);
            let mut split = key.split('.');
            match (split.next(), &mut header) {
                (Some(cur), &mut Value::Table(ref mut hdr)) =>
                    insert_key_into(String::from(cur), &mut split, Cow::Owned(value), hdr),
                _ => { }
            }
        }
    }

    debug!("Header = {:?}", header);
    header
}

fn insert_key_into<'a>(current: String,
                   rest_path: &mut Split<char>,
                   value: Cow<'a, str>,
                   map: &mut Map<String, Value>) {
    let next = rest_path.next();

    if next.is_none() {
        debug!("Inserting into {:?} = {:?}", current, value);
        map.insert(current, parse_value(value));
    } else {
        debug!("Inserting into {:?} ... = {:?}", current, value);
        match map.entry(current) {
            Entry::Occupied(ref mut e) => {
                match *e.get_mut() {
                    Value::Table(ref mut t) => {
                        insert_key_into(String::from(next.unwrap()), rest_path, value, t);
                    },
                    _ => unreachable!(),
                }
            },
            Entry::Vacant(v) => { v.insert(Value::Table( {
                let mut submap = Map::new();
                insert_key_into(String::from(next.unwrap()), rest_path, value, &mut submap);
                debug!("Inserting submap = {:?}", submap);
                submap }));
            }
        }
    }
}

fn parse_value(value: Cow<str>) -> Value {
    use std::str::FromStr;

    fn is_ary(v: &str) -> bool {
        v.starts_with('[') && v.ends_with(']') && v.len() >= 3
    }

    if value == "true" {
        debug!("Building Boolean out of: {:?}...", value);
        Value::Boolean(true)
    } else if value == "false" {
        debug!("Building Boolean out of: {:?}...", value);
        Value::Boolean(false)
    } else if is_ary(&value) {
        debug!("Building Array out of: {:?}...", value);
        let sub = &value[1..(value.len()-1)];
        Value::Array(sub.split(',').map(|x| parse_value(Cow::from(x))).collect())
    } else {
        FromStr::from_str(&value[..])
            .map(|i: i64| {
                debug!("Building Integer out of: {:?}...", value);
                Value::Integer(i)
            })
            .unwrap_or_else(|_| {
                FromStr::from_str(&value[..])
                    .map(|f: f64| {
                        debug!("Building Float out of: {:?}...", value);
                        Value::Float(f)
                    })
                    .unwrap_or_else(|_| {
                        debug!("Building String out of: {:?}...", value);
                        Value::String(value.into_owned())
                    })
            })
    }
}