Skip to main content

Module config_api

Module config_api 

Source
Expand description

Top-level document wrapper for reading and writing libconfig data.

triceratops logo

§Config API Documentation

The Config struct is the primary entry point for working with libconfig data. It wraps a Value and tracks whether the top-level group uses implicit format (no braces) or explicit format ({...}).

§Overview

pub struct Config {
    pub value: Value,
    pub explicit_braces: bool,
}

Config derefs to Value, so all Value methods (indexing, lookup, set, remove, type checks) work directly on a Config.

§Creating a Config

§Empty Config

use libconfig::{Config, Value};

let mut config = Config::new();
config.set("name", Value::String("My App".into()));
config.set("version", Value::Integer(1));
config.set("debug", Value::Bool(false));

assert_eq!(config["name"], "My App");
assert_eq!(config["version"], 1);

Config::new() creates an empty group with explicit_braces: false.

§Parsing a String

use libconfig::Config;

// Implicit group (no outer braces) - the standard config file style
let config = Config::from_str("name = \"My App\";\nversion = 1;").unwrap();
assert!(!config.explicit_braces);
assert_eq!(config["name"], "My App");

// Explicit group (with outer braces) - detected automatically
let config = Config::from_str("{\n  name = \"My App\";\n  version = 1;\n}").unwrap();
assert!(config.explicit_braces);
assert_eq!(config["name"], "My App");

§Reading a File

use libconfig::Config;

let config = Config::from_file("settings.cfg").unwrap();
println!("{}", config["database.host"]);

Config::from_file reads the file and calls Config::from_str, so explicit_braces is detected automatically.

§Wrapping an Existing Value

use libconfig::{Config, Value};

let v = Value::from_str("{ name = \"test\"; }").unwrap();
let config = Config::from(v);

assert!(!config.explicit_braces); // From<Value> always sets implicit
assert_eq!(config["name"], "test");

Config::from(value) always sets explicit_braces to false. Values created programmatically never have explicit braces.

§Default

use libconfig::Config;

let config = Config::default(); // Same as Config::new()
assert!(config.is_group());
assert_eq!(config.as_group().unwrap().len(), 0);

§Serialization

§Config::to_string

Serializes the config to a libconfig string, respecting the explicit_braces setting:

use libconfig::Config;

// Implicit format (no outer braces)
let config = Config::from_str("name = \"test\";\nversion = 42;").unwrap();
let output = config.to_string().unwrap();
assert_eq!(output, "name = \"test\";\nversion = 42;");

// Explicit format (with outer braces)
let config = Config::from_str("{\n  name = \"test\";\n  version = 42;\n}").unwrap();
let output = config.to_string().unwrap();
assert!(output.starts_with('{'));
assert!(output.ends_with('}'));

§Display

Config implements Display, so it can be used with format! and println!:

use libconfig::Config;

let config = Config::from_str("x = 10; y = 20;").unwrap();
println!("{}", config);
// x = 10;
// y = 20;

§Serde Serialize

Config implements Serialize, which always produces output with outer braces (standard serde behavior):

use libconfig::Config;

let config = Config::from_str("a = 1; b = 2;").unwrap();

// Serde to_string always adds braces
let serde_output = libconfig::to_string(&config).unwrap();
assert!(serde_output.starts_with('{'));

// Config::to_string respects the original format
let format_output = config.to_string().unwrap();
assert!(!format_output.starts_with('{'));

§Controlling Outer Braces

The explicit_braces field is public and can be set directly:

use libconfig::{Config, Value};

// Start with implicit format
let mut config = Config::new();
config.set("key", Value::Integer(42));

let implicit = config.to_string().unwrap();
assert_eq!(implicit, "key = 42;");

// Switch to explicit format
config.explicit_braces = true;

let explicit = config.to_string().unwrap();
assert!(explicit.starts_with('{'));
assert!(explicit.contains("key = 42"));
assert!(explicit.ends_with('}'));

§Reading Values

Since Config derefs to Value, all Value access methods work directly:

§Indexing

use libconfig::Config;

let config = Config::from_str("name = \"test\"; ports = [80, 443];").unwrap();

assert_eq!(config["name"], "test");
assert_eq!(config["ports"][0], 80);

§Path Lookup

use libconfig::Config;

let config = Config::from_str(r#"
    database = {
        host = "localhost";
        credentials = {
            username = "admin";
        };
    };
"#).unwrap();

assert_eq!(
    config.lookup("database.credentials.username").unwrap().as_str(),
    Some("admin")
);

// Bracket notation for array indices
assert_eq!(
    config.lookup("database.host").unwrap().as_str(),
    Some("localhost")
);

§Type Checks and Conversions

use libconfig::Config;

let config = Config::from_str("count = 42; name = \"test\";").unwrap();

assert!(config["count"].is_i32());
assert_eq!(config["count"].as_i32(), Some(42));
assert_eq!(config["name"].as_str(), Some("test"));

// Config itself is always a group
assert!(config.is_group());

§Writing Values

§Setting Values

use libconfig::{Config, Value};

let mut config = Config::new();

// Set scalar values
config.set("name", Value::String("My App".into()));
config.set("version", Value::Integer(1));
config.set("pi", Value::Float(3.14159));
config.set("debug", Value::Bool(true));
config.set("big_number", Value::Integer64(100000000000));

// Set arrays and lists
config.set("ports", Value::Array(vec![
    Value::Integer(80),
    Value::Integer(443),
]));

// Auto-create intermediate groups
config.set("database.host", Value::String("localhost".into()));
config.set("database.port", Value::Integer(5432));

assert_eq!(config["database.host"], "localhost");
assert_eq!(config["database.port"], 5432);

§Modifying Existing Values

use libconfig::{Config, Value};

let mut config = Config::from_str("name = \"old\"; version = 1;").unwrap();

// Overwrite via set
config.set("name", Value::String("new".into()));
assert_eq!(config["name"], "new");

// Overwrite via lookup_mut
*config.lookup_mut("version").unwrap() = Value::Integer(2);
assert_eq!(config["version"], 2);

§Removing Values

use libconfig::{Config, Value};

let mut config = Config::from_str("a = 1; b = 2; c = 3;").unwrap();

let removed = config.remove("b");
assert_eq!(removed, Some(Value::Integer(2)));
assert!(config.lookup("b").is_none());
assert_eq!(config["a"], 1);
assert_eq!(config["c"], 3);

§Round-Trip Preservation

Config preserves both key ordering and brace format through round-trips:

use libconfig::Config;

// Implicit format round-trip
let input = "zebra = 1;\napple = 2;\nmonkey = 3;";
let config = Config::from_str(input).unwrap();
let output = config.to_string().unwrap();
assert_eq!(output, input); // Exact match, order preserved

// Explicit format round-trip
let input = "{\n  name = \"test\";\n  version = 42;\n}";
let config = Config::from_str(input).unwrap();
let output = config.to_string().unwrap();
assert_eq!(output, input); // Braces and indentation preserved

§Indentation

Nested groups are indented with 2 spaces per level:

use libconfig::{Config, Value};

let mut config = Config::new();
config.set("server.listen.host", Value::String("0.0.0.0".into()));
config.set("server.listen.port", Value::Integer(8080));

let output = config.to_string().unwrap();
// server = {
//   listen = {
//     host = "0.0.0.0";
//     port = 8080;
//   };
// };

§Config vs Value

ConfigValue
PurposeDocument-level wrapperIndividual data values
Tracks bracesYes (explicit_braces)No
from_strDetects implicit/explicitAlways parses
to_stringFormat-aware (implicit/explicit)Always wraps groups in braces
ConstructionConfig::new(), Config::from_str()Value::Integer(42), Value::String(...)
File I/OConfig::from_file()No

Use Config when working with complete configuration documents. Use Value variants when constructing individual values to pass to Config::set().