| Crates.io | yini-rs |
| lib.rs | yini-rs |
| version | 0.1.0 |
| created_at | 2025-08-12 21:50:57.140512+00 |
| updated_at | 2025-08-12 21:50:57.140512+00 |
| description | A YINI (Yet another INI) parser and writer for Rust |
| homepage | |
| repository | https://github.com/zKiwiko/yini-rs |
| max_upload_size | |
| id | 1792955 |
| size | 42,655 |
A fast, safe Rust parser and writer for the YINI (Yet Another INI) configuration file format. YINI extends the traditional INI format with visual nesting, arrays, and improved readability.
// line comments and /* */ multiline commentsYINI uses a simple but powerful syntax:
# Root-level properties
app_name = 'MyApp'
version = '1.0.0'
debug = true
^ server # Accessed with parser.section("server")
host = 'localhost'
port = 8080
^^ database # Accessed with parser.section("server").section("database")
host = 'db.example.com'
port = 5432
^^^ credentials # Accessed with parser.section("server").section("database").section("credentials")
username = 'admin'
password = 'secret'
^ features
enabled = ['auth', 'logging', 'cache'] # Arrays with []
flags = [true, false, true]
numbers = [1, 2, 3, 4, 5]
'single quotes' or "double quotes"42, -103.14, -2.5true, false, yes, no, on, off[item1, item2, item3]// This is a commentkey = value // Comment here/* This is a multiline comment *//*
* This is a longer comment
* that spans multiple lines
*/
Add this to your Cargo.toml:
[dependencies]
yini-rs = "0.1.0"
use yini_rs::{Parser, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new configuration
let mut config = Parser::new();
// Set values
config["app_name"] = Value::from("MyApplication");
config["port"] = Value::from(8080);
config["debug"] = Value::from(true);
// Create nested sections
config.section("database")["host"] = Value::from("localhost");
config.section("database")["port"] = Value::from(5432);
// Create arrays
let features = vec![
Value::from("auth"),
Value::from("logging")
];
config["features"] = Value::from(features);
// Write to file
config.write_file("config.yini")?;
// Read from file
let mut reader = Parser::new();
reader.parse_file("config.yini")?;
// Access values
println!("App: {}", reader["app_name"].as_string()?);
println!("Port: {}", reader["port"].as_int()?);
println!("Debug: {}", reader["debug"].as_bool()?);
// Access nested values
println!("DB Host: {}", reader.section("database")["host"].as_string()?);
Ok(())
}
ParserMain struct for parsing and writing YINI files.
Methods:
parse_file(&mut self, filename: &str) -> Result<()> - Parse a YINI fileparse_string(&mut self, content: &str) -> Result<()> - Parse YINI content from stringwrite_file(&self, filename: &str) -> Result<()> - Write configuration to filewrite_string(&self) -> String - Write configuration to stringroot(&self) -> &Section - Access the root sectionroot_mut(&mut self) -> &mut Section - Access the root section mutablysection(&mut self, name: &str) -> &mut Section - Access or create a sectionValueRepresents a configuration value with automatic type conversion.
Type checking:
is_string(&self) -> boolis_int(&self) -> boolis_double(&self) -> boolis_bool(&self) -> boolis_array(&self) -> boolValue access:
as_string(&self) -> Result<String>as_int(&self) -> Result<i32>as_double(&self) -> Result<f64>as_bool(&self) -> Result<bool>as_array(&self) -> Result<Vec<Value>>SectionRepresents a configuration section containing values and subsections.
Methods:
Index<&str> for value[key] accessat(&self, key: &str) -> Result<&Value> - Safe value accesshas_value(&self, key: &str) -> bool - Check if value existssection(&mut self, name: &str) -> &mut Section - Access or create subsectionget_section(&self, name: &str) -> Result<&Section> - Get subsection (read-only)has_section(&self, name: &str) -> bool - Check if section existsError::ParseError - Returned when parsing failsError::FileError - Returned when file operations failError::TypeError - Returned for type conversion errorsError::KeyNotFound - Returned when accessing non-existent keysError::SectionNotFound - Returned when accessing non-existent sectionsuse yini_rs::{Parser, Value};
let mut parser = Parser::new();
parser.parse_string(r#"
numbers = [1, 2, 3, 4, 5]
names = ['alice', 'bob', 'charlie']
mixed = [true, 42, 'hello', 3.14]
"#)?;
let numbers = parser["numbers"].as_array()?;
for num in &numbers {
println!("Number: {}", num.as_int()?);
}
use yini_rs::{Parser, Error};
let mut parser = Parser::new();
// Parse errors are returned as Results
match parser.parse_string("invalid syntax") {
Err(Error::ParseError { message }) => {
println!("Parse error: {}", message);
}
_ => {}
}
// Missing key errors
match parser.root().at("nonexistent") {
Err(Error::KeyNotFound { key }) => {
println!("Key '{}' not found", key);
}
_ => {}
}
use yini_rs::{Parser, Value};
let mut parser = Parser::new();
parser.parse_string(r#"
string_number = '42'
string_bool = 'true'
int_value = 100
"#)?;
// Automatic type conversion
let num: i32 = parser["string_number"].as_int()?; // "42" -> 42
let flag: bool = parser["string_bool"].as_bool()?; // "true" -> true
let text: String = parser["int_value"].as_string()?; // 100 -> "100"
Simply add this crate to your Cargo.toml and you're ready to go! To run the tests:
# Run tests
cargo test
# Run examples
cargo run --example basic_usage
# Build documentation
cargo doc --open
YINI-RS is designed for speed and efficiency:
Benchmark results on a 1000-line configuration file:
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under either of
at your option.