Search code examples
rusttoml

How to create a TOML file from Rust?


I have collected all my data into a vector and I need to create a TOML file with that data. I have managed to create and open a file:

let mut file = try!(File::create("servers.toml"));

My vector<(string,(string, u32))> contains the following data, which should look like this in TOML.

[server.A]
Ipaddr="192.168.4.1"
Port no=4476

[server.B]
......

I have a lot of data which needs to be written in TOML and I know TOML is a text file. How is encoder used for?


Solution

  • This uses the TOML crate for the structure and serialization. The main benefit is that values should be properly escaped.

    use std::fs;
    use toml::{map::Map, Value}; // 0.5.1
    
    fn to_toml(v: Vec<(String, (String, u32))>) -> Value {
        let mut servers = Map::new();
        for (name, (ip_addr, port)) in v {
            let mut server = Map::new();
            server.insert("Ipaddr".into(), Value::String(ip_addr));
            server.insert("Port no".into(), Value::Integer(port as i64));
            servers.insert(name, Value::Table(server));
        }
    
        let mut map = Map::new();
        map.insert("server".into(), Value::Table(servers));
        Value::Table(map)
    }
    
    fn main() {
        let v = vec![
            ("A".into(), ("192.168.4.1".into(), 4476)),
            ("B".into(), ("192.168.4.8".into(), 1234)),
        ];
    
        let toml_string = toml::to_string(&to_toml(v)).expect("Could not encode TOML value");
        println!("{}", toml_string);
    
        fs::write("servers.toml", toml_string).expect("Could not write to file!");
    }
    

    You can also use this with Serde's automatic serialization and deserialization to avoid dealing with the low-level details:

    use serde::Serialize; // 1.0.91
    use std::{collections::BTreeMap, fs};
    use toml; // 0.5.1
    
    #[derive(Debug, Default, Serialize)]
    struct Servers<'a> {
        servers: BTreeMap<&'a str, Server<'a>>,
    }
    
    #[derive(Debug, Serialize)]
    struct Server<'a> {
        #[serde(rename = "Ipaddr")]
        ip_addr: &'a str,
    
        #[serde(rename = "Port no")]
        port_no: i64,
    }
    
    fn main() {
        let mut file = Servers::default();
        file.servers.insert(
            "A",
            Server {
                ip_addr: "192.168.4.1",
                port_no: 4476,
            },
        );
        file.servers.insert(
            "B",
            Server {
                ip_addr: "192.168.4.8",
                port_no: 1234,
            },
        );
    
        let toml_string = toml::to_string(&file).expect("Could not encode TOML value");
        println!("{}", toml_string);
        fs::write("servers.toml", toml_string).expect("Could not write to file!");
    }