1use 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}