Expand description
§NOML - Nested Object Markup Language
NOML is a modern configuration language that combines the simplicity of TOML with advanced features like environment variables, file inclusion, variable interpolation, native types, HTTP includes, and schema validation.
§Quick Start
use noml::{parse, Value};
let source = r#"
name = "my-app"
version = "1.0.0"
debug = true
database_url = env("DATABASE_URL", "sqlite:memory:")
max_file_size = @size("10MB")
timeout = @duration("30s")
server_ip = @ip("127.0.0.1")
[server]
host = "0.0.0.0"
port = 8080
[database]
host = "localhost"
port = 5432
"#;
let config = parse(source)?;
// Access values with type safety
assert_eq!(config.get("name").unwrap().as_string().unwrap(), "my-app");
assert_eq!(config.get("server.port").unwrap().as_integer().unwrap(), 8080);
§Core Features
- 🔧 TOML-compatible syntax with extended functionality
- 🌍 Environment variables via
env("VAR_NAME", "default")
- 📁 File inclusion via
include "path/to/file.noml"
- 🌐 HTTP includes via
include "https://example.com/config.noml"
- 🔗 Variable interpolation via
"Hello ${name}!"
- ⚡ Native types like
@size("10MB")
,@duration("30s")
,@ip("127.0.0.1")
- ✅ Schema validation for type safety and error prevention
- 💬 Comment preservation for tooling and round-trip editing
- 🎯 Detailed error reporting with precise source locations
- 🚀 Zero-copy parsing for optimal performance
- 🔄 Async support with tokio integration
§Native Types
NOML includes built-in support for common configuration types:
use noml::parse;
let config = parse(r#"
max_upload = @size("100MB")
cache_size = @size("2GB")
timeout = @duration("30s")
retry_delay = @duration("5m")
api_endpoint = @url("https://api.example.com/v1")
"#)?;
// Native types are automatically converted to appropriate Rust types
§Advanced Configuration Management
use noml::{Config, Schema, FieldType, SchemaBuilder};
// Load configuration with schema validation
let config = Config::from_string(r#"
app_name = "my-service"
port = 8080
debug = false
[database]
host = "localhost"
max_connections = 100
"#)?;
// Define and validate schema
let schema = SchemaBuilder::new()
.require_string("app_name")
.require_integer("port")
.optional_bool("debug")
.build();
config.validate_schema(&schema)?;
// Access with type safety
let port = config.get("port").unwrap().as_integer()?;
let debug = config.get("debug").unwrap_or(&noml::Value::Bool(false)).as_bool()?;
§Async Support
Enable the async
feature for non-blocking operations:
[dependencies]
noml = { version = "0.9", features = ["async"] }
ⓘ
use noml::{parse_async, Config};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse with HTTP includes
let config = parse_async(r#"
app_name = "my-app"
include "https://config-server.com/common.noml"
"#).await?;
// Async file operations
let mut config = Config::load_async("config.noml").await?;
config.set("updated_at", chrono::Utc::now().to_rfc3339())?;
config.save_async().await?;
Ok(())
}
§Error Handling
NOML provides detailed error information for debugging:
use noml::parse;
let result = parse(r#"
invalid_syntax = [ # Missing closing bracket
"#);
match result {
Err(e) => {
println!("Parse error: {}", e);
// Error contains source location information
}
Ok(_) => unreachable!(),
}
§Advanced Usage
use noml::{Resolver, ResolverConfig, parse_string};
use std::collections::HashMap;
// Custom environment variables
let mut env_vars = HashMap::new();
env_vars.insert("APP_NAME".to_string(), "my-app".to_string());
// Custom resolver configuration
let config = ResolverConfig {
env_vars: Some(env_vars),
allow_missing_env: true,
..Default::default()
};
let mut resolver = Resolver::with_config(config);
let document = parse_string(r#"name = env("APP_NAME")"#, None)?;
let value = resolver.resolve(&document)?;
assert_eq!(value.get("name").unwrap().as_string().unwrap(), "my-app");
Re-exports§
pub use config::Config;
pub use error::NomlError;
pub use error::Result;
pub use parser::ast::AstNode;
pub use parser::parse_file;
pub use parser::parse_string;
pub use parser::Document;
pub use resolver::NativeResolver;
pub use resolver::Resolver;
pub use resolver::ResolverConfig;
pub use serializer::serialize_document;
pub use serializer::serialize_document_with_options;
pub use serializer::Serializer;
pub use value::Value;
pub use schema::FieldSchema;
pub use schema::FieldType;
pub use schema::Schema;
pub use schema::SchemaBuilder;
Modules§
- config
- NOML Configuration Management
- error
- Error Handling
- macros
- NOML Macros
- parser
- NOML Parser Module
- resolver
- NOML Resolver
- schema
- NOML Schema Validation
- serializer
- Format-Preserving NOML Serializer
- value
- NOML Value System
Macros§
- noml_
value - Create a NOML value using a convenient macro syntax
Functions§
- modify_
preserving - Modify a NOML document while preserving formatting.
- parse
- Parse NOML from a string and resolve all dynamic features
- parse_
from_ file - Parse NOML from a file and resolve all dynamic features
- parse_
preserving - Create a NOML value using a convenient macro syntax
- parse_
preserving_ from_ file - Parse NOML from a file with full format preservation.
- parse_
raw - Parse NOML from a string without resolving dynamic features
- parse_
raw_ from_ file - Parse NOML from a file without resolving dynamic features
- save_
preserving - Save a NOML document to a file with format preservation.
- validate
- Validate NOML syntax without parsing into values