serde-libconfigasaurus 0.3.2

Serde serialization and deserialization for libconfig format
Documentation
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

| | `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()`.