Top-level document wrapper for reading and writing libconfig data.
<p align="center">
<img src="https://gitlab.com/rustographer/serde-libconfigasaurus/-/raw/main/assets/triceratops.png" alt="triceratops logo" width="300" height="300" >
</p>
# **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
```rust,ignore
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
```rust
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
```rust
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
```rust ,no_run
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
```rust
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
```rust
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:
```rust
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!`:
```rust
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):
```rust
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:
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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
```rust
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:
```rust
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:
```rust
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
| **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()`.