TOML is a simple, ergonomic, and readable configuration format. Rust's package manager cargo uses TOML format. This article explains how to handle TOML format data in Rust.
In Rust, you can use the toml crate to parse and generate TOML format data. Combined with serde and toml, you can parse TOML strings into arbitrary Rust structs or serialize Rust structs into TOML format strings.
Adding Dependencies
To use toml and serde, add these dependencies by editing your Cargo.toml file:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "0.9"
Using the toml Crate
The toml crate provides a toml::Table struct representing TOML tables, which you can use to access and manipulate TOML data:
pub type Table = Map<String, Value>;
Here, Value represents toml::Value, an enum that represents TOML values:
pub enum Value {
String(String),
Integer(i64),
Float(f64),
Boolean(bool),
Datetime(Datetime),
Array(Array),
Table(Table),
}
Here's a simple example demonstrating how to use toml::Table to manipulate TOML tables:
use toml::{Table, Value};
fn main() {
let mut table = Table::new();
// Insert key-value pairs
table.insert("website".to_string(), Value::String("perfcode.com".to_string()));
table.insert("total".to_string(), Value::Integer(100));
table.insert("enabled".to_string(), Value::Boolean(true));
// Get values
let website = table.get("website").unwrap().as_str().unwrap();
let total = table.get("total").unwrap().as_integer().unwrap();
let enabled = table.get("enabled").unwrap().as_bool().unwrap();
println!("website: {}, total: {}, enabled: {}", website, total, enabled);
// Iterate through all key-value pairs
for (key, value) in table.iter() {
println!(" - {}: {:?}", key, value);
}
// Remove a key-value pair
let removed_value = table.remove("total");
println!("removed value: {:?}", removed_value);
}
Program Output
website: perfcode.com, total: 100, enabled: true
- enabled: Boolean(true)
- total: Integer(100)
- website: String("perfcode.com")
removed value: Some(Integer(100))
Parsing TOML Documents
The simplest way to parse TOML documents is through the Table type:
use toml::Table;
fn main() {
let toml_text = r#"
a = "perfcode.com"
b = true
[others]
c = 3
"#;
let value = toml_text.parse::<Table>().unwrap();
println!("{}\n{}\n{}",
value["a"].as_str().unwrap(),
value["b"].as_bool().unwrap(),
value["others"]["c"].as_integer().unwrap(),
);
}
Program Output
perfcode.com true 3
Using toml::from_str Function
The toml crate provides a toml::from_str function to parse (deserialize) TOML documents into toml::Table type. Here's a modified version of the previous example:
use toml::Table;
fn main() {
let toml_text = r#"
a = "perfcode.com"
b = true
[others]
c = 3
"#;
let value: Table = toml::from_str(&toml_text).unwrap();
println!("{}\n{}\n{}",
value["a"].as_str().unwrap(),
value["b"].as_bool().unwrap(),
value["others"]["c"].as_integer().unwrap(),
);
}
Using toml::to_string Function
You can use the toml::to_string function to serialize toml::Table type into a TOML string:
use toml::Table;
fn main() {
let toml_text = r#"
a = "perfcode.com"
"#;
let mut value: Table = toml::from_str(&toml_text).unwrap();
value.insert("b".to_string(), toml::Value::String("www.perfcode.com".to_string()));
let new_toml = toml::to_string(&value).unwrap();
println!("{}", new_toml);
}
Program Output
a = "perfcode.com" b = "www.perfcode.com"
Serializing and Deserializing Custom Structs
An example of TOML deserialization:
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct Config {
ip: String,
port: u16,
others: Others
}
#[derive(Deserialize, Serialize)]
struct Others {
salt: String,
use_whitelist: bool,
}
fn main() {
let tom_text = r#"
ip = "127.0.0.1"
port = 80
[others]
salt = "xxxxxx"
use_whitelist = false
"#;
let config: Config = toml::from_str(tom_text).unwrap();
println!("ip: {}\nport: {}\nsalt: {}\nuse_whitelist: {}",
config.ip,
config.port,
config.others.salt,
config.others.use_whitelist
);
}
Program Output
ip: 127.0.0.1 port: 80 salt: xxxxxx use_whitelist: false
An example of TOML serialization:
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct Config {
ip: String,
port: u16,
others: Others
}
#[derive(Deserialize, Serialize)]
struct Others {
salt: String,
use_whitelist: bool,
}
fn main() {
// Serialization
let new_config = Config {
ip: "0.0.0.0".to_string(),
port: 80,
others: Others {
salt: "ssssssssss".to_string(),
use_whitelist: true
}
};
let new_toml = toml::to_string(&new_config).unwrap();
println!("{}", new_toml);
}
Program Output
ip = "0.0.0.0" port = 80 [others] salt = "ssssssssss" use_whitelist = true