AAM (Abstract Alias Mapping)
A robust and lightweight configuration parser for Rust that supports key-value pairs, recursive dependency resolution, file imports, and bidirectional lookups. Designed for applications that need flexible configuration files with references, aliases, and a modular structure.
Features
- Simple syntax: A
key = valueformat that is easy to read and write. - Import support: The
@importdirective lets you split configuration into multiple files. - Comments support: Lines starting with
#are treated as comments. - Deep resolution (
find_deep): Automatically resolves chains of references (e.g.,A -> B -> C) to find the final value. - Loop detection: Safely handles circular dependencies (e.g.,
A -> B -> A) without stack overflows. - Bidirectional lookup (
find_obj): Looks up a value by key, or performs a reverse lookup (finds a key by value) when the key is missing. - Config builder (
AAMBuilder): Programmatically generate and save.aamfiles. - Configuration merging: Supports the
+operator to combine twoAAMLinstances. - Typed errors: Detailed parsing and I/O error handling via
AamlError.
Format
You can find documentation and examples for the format in the docs
Installation
Add the library to your Cargo.toml:
[]
= "1.0.5"
Configuration syntax (.aam)
The format is line-based. Whitespace around keys and values is trimmed. Strings can be quoted.
# This is a comment
host = "localhost"
port = 8080
# Import other configuration files
@import "database.aam"
@import "theme.aam"
# You can define aliases for deep lookup
base_path = /var/www
current_path = base_path
# Circular references are handled safely
loop_a = loop_b
loop_b = loop_a
Usage guide
1) Parsing and loading
You can parse configuration from a string, load it from a file, or merge multiple sources. Errors are handled via AamlError.
use AAML;
use AamlError;
2) Merging configurations
Combine different AAML objects using the addition operator.
let mut config1 = AAMLparse?;
let config2 = AAMLparse?;
// Merge (config2 overwrites matching keys in config1)
config1 += config2;
// or: let config3 = config1 + config2;
3) Smart lookup (find_obj)
find_obj is a hybrid lookup method. It first tries to find a value by the given key. If the key does not exist, it searches for a key whose value matches the provided string.
let content = "
# Key = Value
app_mode = production
debug = false
";
let config = AAMLparse?;
// Scenario A: Direct key lookup
let mode = config.find_obj.unwrap;
assert_eq!;
// Scenario B: Reverse lookup
// "production" is not a key, so it looks for a key with value "production"
let key = config.find_obj.unwrap;
assert_eq!;
4) Deep recursive lookup (find_deep)
This is useful for aliasing. It follows values as keys until it reaches a value that is not present as a key, or until a loop is detected.
let content = "
root = /usr/bin
executable = root
service = executable
";
let config = AAMLparse?;
// Traces: "service" -> "executable" -> "root" -> "/usr/bin"
let final_val = config.find_deep.unwrap;
assert_eq!;
Handling loops: If the configuration contains a loop (e.g., a=b, b=a), find_deep returns the last unique value visited before the loop closes, preventing infinite recursion.
5) Building configurations (AAMBuilder)
Use AAMBuilder to generate configuration files programmatically.
use ;
let mut builder = new;
builder.comment
.type_alias
.schema
.add_line
.add_line;
// Save to file
builder.to_file;
// Or convert to string
println!;
6) Working with FoundValue
Lookup results are wrapped in a FoundValue struct. It implements Deref<Target=String> and Display, so you can use it like a regular &str or String. It also provides helper methods for in-place modification.
let config = AAMLparse?;
let mut value = config.find_obj.unwrap;
// Use as a string
println!; // Prints: Hello World
// Modify in-place using the helper method
value.remove;
assert_eq!;
API reference
AAML
parse(content: &str) -> Result<Self, AamlError>: Parses a string into an AAML map.load<P: AsRef<Path>>(file_path: P) -> Result<Self, AamlError>: Loads and parses a file, handling imports.merge_content(&mut self, content: &str) -> Result<(), AamlError>: Merges content into the current instance.merge_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), AamlError>: Reads a file and merges it.find_obj(&self, key: &str) -> Option<FoundValue>: Smart bidirectional lookup.find_deep(&self, key: &str) -> Option<FoundValue>: Recursive lookup with loop detection.find_key(&self, value: &str) -> Option<FoundValue>: Strict reverse lookup (find key by value).
AAMBuilder
new() -> Self: Creates a new builder.add_line(key: &str, value: &str): Adds akey = valuepair.comment(text: &str): Adds a# textcomment line.schema(name: &str, fields: impl IntoIterator<Item = SchemaField>): Adds a@schema Name { ... }directive (inline).schema_multiline(name: &str, fields: impl IntoIterator<Item = SchemaField>): Adds a@schema Name { ... }directive (one field per line).derive(path: &str, schemas: impl IntoIterator<Item = impl AsRef<str>>): Adds a@derive path[::Schema...]directive.import(path: &str): Adds a@import pathdirective.type_alias(alias: &str, type_name: &str): Adds a@type alias = type_namedirective.add_raw(raw_line: &str)(deprecated): Adds a raw line as-is. Prefer the typed methods above.to_file<P: AsRef<Path>>(&self, path: P): Writes the buffer to a file.
AamlError
IoError: Wraps standard I/O errors.ParseError: Syntax errors (includes line number and details).NotFound: Key not found (internal use).
License
See the LICENSE file.