4 releases (2 breaking)
Uses new Rust 2024
| 0.3.0 | Jan 25, 2026 |
|---|---|
| 0.2.1 | Jan 22, 2026 |
| 0.2.0 | Jan 21, 2026 |
| 0.1.0 | Jan 20, 2026 |
#476 in Encoding
Used in 3 crates
635KB
15K
SLoC
ron-extras
A RON parser with full AST access, schema-driven LSP completions, and formatting tools.
Quick Start
[dependencies]
ron2 = "0.3"
use ron2::{FromRon, Ron};
#[derive(Ron, Debug)]
struct Config {
/// Server port
port: u16,
/// Optional hostname
host: Option<String>,
}
fn main() -> ron2::Result<()> {
let config = Config::from_ron("(port: 8080, host: \"localhost\")")?;
println!("{:?}", config);
Ok(())
}
See Derive Attributes for the full attribute reference.
Crates
| Crate | Description |
|---|---|
ron2 |
Core parser with AST and Value APIs |
ron2-derive |
Derive macros for FromRon, ToRon, and schema generation |
ron2-lsp |
Language server with completions and diagnostics |
ron2-doc |
Documentation generator from schema files |
ron2-cli |
CLI tools (ron fmt, ron doc) |
Why ron2?
- AST-first: Parses to a complete AST preserving all source information
- Perfect round-trip: Preserves comments, whitespace, and formatting exactly
- Rich errors: Full source spans enable beautiful error messages (see Error Reporting)
- Full RON data model: Avoids serde limitations through custom derive
ron2 works best for human-edited config files or building custom DSLs. See the showcase example for a complete demonstration of derive macros, schema validation, and formatting.
Error Reporting
ron2 provides full source spans on all parsed values via the Spanned<T> wrapper. This enables beautiful error messages with libraries like ariadne:
#[derive(FromRon)]
struct ServerConfig {
host: Spanned<String>,
port: Spanned<u16>,
max_connections: Spanned<u32>,
}
// Access value and span separately
if config.port.value == 0 {
report_error("port cannot be 0", config.port.span);
}
Error: max_connections (10) must be >= min_connections (100)
╭─[ config.ron:5:22 ]
│
5 │ max_connections: 10,
│ ─┬
│ ╰── max_connections (10) must be >= min_connections (100)
│
│ Help: increase max_connections or decrease min_connections
───╯
See the error-report example for a complete implementation.
Schema & LSP
ron2 can generate schema files from your Rust types. The LSP uses these schemas for completions and validation.
Generate schemas by calling write_schemas (e.g., from a test or a dedicated binary):
use ron2::schema::RonSchema;
// Write to a specific directory
Config::write_schemas(Some("./schemas"))?;
// Or use the default XDG location (~/.local/share/ron-schemas/)
Config::write_schemas(None)?;
The LSP searches for schemas in this order:
- Configured
schemaDirs(from editor settings) RON_SCHEMA_DIRenvironment variable- XDG default (
~/.local/share/ron-schemas/)
Add the #![type] attribute to your RON files to enable completions:
#![type = "my_crate::config::Config"]
(
port: 8080,
host: "localhost",
)
CLI Tools
Install the CLI:
cargo install ron2-cli
Format RON files:
ron fmt config.ron # Format in place
ron fmt --check config.ron # Check formatting (for CI)
Generate documentation from schemas:
ron doc ./schemas -o ./docs
When Not to Use ron2
Don't use ron2 if:
- You need serde compatibility (your types only implement Serialize/Deserialize)
- You're parsing large data volumes where speed matters more than AST fidelity
Alternatives:
Editor Setup
See EDITOR_SETUP.md for Helix, VS Code, and other editor integrations.
Acknowledgments & License
Derived from ron. Dual-licensed under Apache-2.0 and MIT.
lib.rs:
RON2 - Rusty Object Notation parser with full AST access
This crate provides a standalone RON parser with three APIs:
- AST API: Full fidelity parsing with perfect round-trip support
- Value API: Simplified access to semantic content only
- Typed Conversions:
FromRonandToRontraits for Rust types
No serde dependency required.
AST Example (full fidelity)
use ron2::ast::{parse_document, serialize_document};
let source = "// config\nPoint(x: 1, y: 2)";
let doc = parse_document(source).unwrap();
let output = serialize_document(&doc).unwrap();
assert_eq!(source, output); // Perfect round-trip
Value Example (semantic only)
use ron2::Value;
let value: Value = "[1, 2, 3]".parse().unwrap();
assert!(matches!(value, Value::Seq(_)));
Typed Conversions
use ron2::{FromRon, ToRon};
let numbers: Vec<i32> = Vec::from_ron("[1, 2, 3]").unwrap();
assert_eq!(numbers, vec![1, 2, 3]);
let ron_string = numbers.to_ron().unwrap();
Dependencies
~1.3–3.5MB
~62K SLoC