Rust LogoTOML

TOML (Tom's Obvious, Minimal Language) is a configuration file format designed to be easy to read due to its clear semantics. Its primary goal is to be a minimal configuration file format that maps cleanly to a hash table (or dictionary) structure. It was created by Tom Preston-Werner, one of the co-founders of GitHub.

Key features and characteristics of TOML include:

* Human-readable and Easy to Write: TOML's syntax is straightforward and intuitive, making it easy for humans to read and write configuration files without significant effort or specialized tools.
* Strongly Typed: TOML supports various data types, including strings, integers, floats, booleans, datetime objects (local, offset, and local date/time), arrays, and tables (analogous to objects or dictionaries). This type safety helps prevent configuration errors.
* Hierarchical Structure: Configurations are organized into tables, which are similar to sections in INI files or objects in JSON. Tables can be nested to create hierarchical structures using dot notation or explicit `[table]` headers.
* Arrays: TOML supports arrays of primitive types and tables, allowing for lists of configurations.
* Comments: TOML allows single-line comments starting with `#`, which improves documentation within configuration files.
* Minimalism: TOML strives for minimalism, providing just enough features to represent configuration data effectively without becoming overly complex or verbose.

Compared to other popular configuration formats:
* JSON: TOML is often considered more human-friendly for manual editing than JSON due to less strict quoting rules for keys and fewer braces/brackets.
* YAML: TOML is generally less verbose and has a simpler specification than YAML, making it easier to parse and often preferred for simpler configurations where YAML's advanced features (like anchors, aliases) are not needed.
* INI: TOML can be seen as a more modern and type-safe successor to INI files, offering better support for nested structures and a wider range of data types.

TOML is widely used in the Rust ecosystem, most notably for the `Cargo.toml` file, which defines Rust project metadata and dependencies. For Rust applications, the `toml` crate, often used in conjunction with `serde` (for serialization/deserialization), provides robust functionality for parsing TOML files into Rust structs and vice-versa.

Example Code

// Cargo.toml dependencies:
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// toml = "0.8"

use serde::{Deserialize, Serialize};
use std::fs;

// Define a Rust struct that will map to our TOML configuration
#[derive(Debug, Deserialize, Serialize)]
struct Config {
    title: String,
    owner: Owner,
    database: Database,
    servers: Servers,
}

#[derive(Debug, Deserialize, Serialize)]
struct Owner {
    name: String,
    dob: Option<toml::value::Datetime>, // Using Option for optional fields
}

#[derive(Debug, Deserialize, Serialize)]
struct Database {
    server: String,
    ports: Vec<u16>,
    connection_max: u32,
    enabled: bool,
}

#[derive(Debug, Deserialize, Serialize)]
struct Servers {
    alpha: ServerInfo,
    beta: ServerInfo,
}

#[derive(Debug, Deserialize, Serialize)]
struct ServerInfo {
    ip: std::net::IpAddr, // Example of using standard library types
    dc: String,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // --- 1. Parsing TOML from a string ---
    let toml_content = r#"
        title = "TOML Example"

        [owner]
        name = "Tom Preston-Werner"
        dob = 1979-05-27T07:32:00-08:00 # First-party date/time type

        [database]
        server = "192.168.1.1"
        ports = [ 8001, 8002, 8003 ]
        connection_max = 5000
        enabled = true

        [servers]

        [servers.alpha]
        ip = "10.0.0.1"
        dc = "eqdc10"

        [servers.beta]
        ip = "10.0.0.2"
        dc = "eqdc10"
    "#;

    println!("--- Parsing TOML content ---");
    let parsed_config: Config = toml::from_str(toml_content)?;
    println!("Parsed config: {:#?}", parsed_config);

    // --- 2. Modifying and serializing a Rust struct to TOML ---
    println!("\n--- Modifying config and serializing to TOML ---");
    let mut new_config = parsed_config;
    new_config.owner.name = "Jane Doe".to_string();
    new_config.servers.alpha.dc = "us-east-1".to_string();
    new_config.database.ports.push(8004);

    let serialized_toml = toml::to_string_pretty(&new_config)?;
    println!("Serialized TOML:\n{}", serialized_toml);

    // --- 3. Example of writing to a file (optional) ---
    // In a real application, you might write this to a file.
    let file_path = "config.toml";
    fs::write(file_path, serialized_toml)?;
    println!("\nConfiguration written to '{}'", file_path);

    // You could then read it back to demonstrate file parsing
    let read_from_file_content = fs::read_to_string(file_path)?;
    let config_from_file: Config = toml::from_str(&read_from_file_content)?;
    println!("\nConfig read from file: {:#?}", config_from_file);

    Ok(())
}