Expand description
Top-level document wrapper for reading and writing libconfig data.
§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
Config | Value | |
|---|---|---|
| Purpose | Document-level wrapper | Individual data values |
| Tracks braces | Yes (explicit_braces) | No |
from_str | Detects implicit/explicit | Always parses |
to_string | Format-aware (implicit/explicit) | Always wraps groups in braces |
| Construction | Config::new(), Config::from_str() | Value::Integer(42), Value::String(...) |
| File I/O | Config::from_file() | No |
Use Config when working with complete configuration documents. Use Value variants when constructing individual values to pass to Config::set().