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