ucglib/convert/
toml.rs

1// Copyright 2018 Jeremy Wall
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std;
16use std::error;
17use std::error::Error;
18use std::io::Write;
19use std::rc::Rc;
20
21use simple_error::SimpleError;
22use toml;
23
24use crate::build::Val;
25use crate::convert::traits::{ConvertResult, Converter, ImportResult, Importer};
26
27pub struct TomlConverter {}
28
29type Result = std::result::Result<toml::Value, Box<dyn error::Error>>;
30
31impl TomlConverter {
32    pub fn new() -> Self {
33        TomlConverter {}
34    }
35
36    fn convert_list(&self, items: &Vec<Rc<Val>>) -> Result {
37        let mut v = Vec::new();
38        for val in items.iter() {
39            v.push(self.convert_value(val)?);
40        }
41        Ok(toml::Value::Array(v))
42    }
43
44    fn convert_tuple(&self, items: &Vec<(String, Rc<Val>)>) -> Result {
45        let mut mp = toml::value::Table::new();
46        for &(ref k, ref v) in items.iter() {
47            mp.entry(k.clone()).or_insert(self.convert_value(v)?);
48        }
49        Ok(toml::Value::Table(mp))
50    }
51
52    fn convert_env(&self, items: &Vec<(String, String)>) -> Result {
53        let mut mp = toml::value::Table::new();
54        for &(ref k, ref v) in items.iter() {
55            mp.entry(k.clone())
56                .or_insert(toml::Value::String(v.clone()));
57        }
58        Ok(toml::Value::Table(mp))
59    }
60
61    fn convert_value(&self, v: &Val) -> Result {
62        let toml_val = match v {
63            &Val::Boolean(b) => toml::Value::Boolean(b),
64            &Val::Empty => {
65                let err = SimpleError::new("Nulls are not allowed in Toml Conversions!");
66                return Err(Box::new(err));
67            }
68            &Val::Float(f) => toml::Value::Float(f),
69            &Val::Int(i) => toml::Value::Integer(i),
70            &Val::Str(ref s) => toml::Value::String(s.clone()),
71            &Val::Env(ref fs) => self.convert_env(fs)?,
72            &Val::List(ref l) => self.convert_list(l)?,
73            &Val::Tuple(ref t) => self.convert_tuple(t)?,
74        };
75        Ok(toml_val)
76    }
77
78    fn convert_toml_val(&self, v: &toml::Value) -> std::result::Result<Val, Box<dyn Error>> {
79        Ok(match v {
80            toml::Value::String(s) => Val::Str(s.clone()),
81            toml::Value::Integer(i) => Val::Int(*i),
82            toml::Value::Float(f) => Val::Float(*f),
83            toml::Value::Boolean(b) => Val::Boolean(*b),
84            toml::Value::Array(l) => {
85                let mut vs = Vec::with_capacity(l.len());
86                for aval in l {
87                    vs.push(Rc::new(self.convert_toml_val(aval)?));
88                }
89                Val::List(vs)
90            }
91            toml::Value::Table(m) => {
92                let mut fs = Vec::with_capacity(m.len());
93                for (key, value) in m {
94                    fs.push((key.to_string(), Rc::new(self.convert_toml_val(value)?)));
95                }
96                Val::Tuple(fs)
97            }
98            toml::Value::Datetime(d) => Val::Str(format!("{}", d)),
99        })
100    }
101
102    fn write(&self, v: &Val, w: &mut dyn Write) -> ConvertResult {
103        let toml_val = self.convert_value(v)?;
104        let toml_bytes = toml::ser::to_string_pretty(&toml_val)?;
105        write!(w, "{}", toml_bytes)?;
106        Ok(())
107    }
108}
109
110impl Converter for TomlConverter {
111    fn convert(&self, v: Rc<Val>, mut w: &mut dyn Write) -> ConvertResult {
112        self.write(&v, &mut w)
113    }
114
115    fn file_ext(&self) -> String {
116        String::from("toml")
117    }
118
119    fn description(&self) -> String {
120        "Convert ucg Vals into valid ucg.".to_string()
121    }
122
123    #[allow(unused_must_use)]
124    fn help(&self) -> String {
125        include_str!("toml_help.txt").to_string()
126    }
127}
128
129impl Importer for TomlConverter {
130    fn import(&self, bytes: &[u8]) -> ImportResult {
131        let json_val = toml::from_slice(bytes)?;
132        Ok(Rc::new(self.convert_toml_val(&json_val)?))
133    }
134}