Skip to content

zKiwiko/yini-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

YINI-RS

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.

Features

  • Zero dependencies: Pure Rust implementation with minimal dependencies
  • Memory safe: Written in 100% safe Rust with no risk of buffer overflows
  • Type support: Strings, integers, doubles, booleans, and arrays
  • Comment support: Both // line comments and /* */ multiline comments
  • Error handling: Comprehensive error handling with detailed messages
  • Round-trip: Parse and write YINI files without data loss

YINI Format

YINI 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]

Supported Types

  • Strings: 'single quotes' or "double quotes"
  • Integers: 42, -10
  • Doubles: 3.14, -2.5
  • Booleans: true, false, yes, no, on, off
  • Arrays: [item1, item2, item3]

Comments

  • Line comments: // This is a comment
  • End-of-line comments: key = value // Comment here
  • Multiline comments: /* This is a multiline comment */
  • Block comments spanning multiple lines:
    /*
     * This is a longer comment
     * that spans multiple lines
     */
    

Installation

Add this to your Cargo.toml:

[dependencies]
yini-rs = "0.1.0"

Usage

Basic Example

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(())
}

API Reference

Parser

Main struct for parsing and writing YINI files.

Methods:

  • parse_file(&mut self, filename: &str) -> Result<()> - Parse a YINI file
  • parse_string(&mut self, content: &str) -> Result<()> - Parse YINI content from string
  • write_file(&self, filename: &str) -> Result<()> - Write configuration to file
  • write_string(&self) -> String - Write configuration to string
  • root(&self) -> &Section - Access the root section
  • root_mut(&mut self) -> &mut Section - Access the root section mutably
  • section(&mut self, name: &str) -> &mut Section - Access or create a section

Value

Represents a configuration value with automatic type conversion.

Type checking:

  • is_string(&self) -> bool
  • is_int(&self) -> bool
  • is_double(&self) -> bool
  • is_bool(&self) -> bool
  • is_array(&self) -> bool

Value 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>>

Section

Represents a configuration section containing values and subsections.

Methods:

  • Implements Index<&str> for value[key] access
  • at(&self, key: &str) -> Result<&Value> - Safe value access
  • has_value(&self, key: &str) -> bool - Check if value exists
  • section(&mut self, name: &str) -> &mut Section - Access or create subsection
  • get_section(&self, name: &str) -> Result<&Section> - Get subsection (read-only)
  • has_section(&self, name: &str) -> bool - Check if section exists

Error Types

  • Error::ParseError - Returned when parsing fails
  • Error::FileError - Returned when file operations fail
  • Error::TypeError - Returned for type conversion errors
  • Error::KeyNotFound - Returned when accessing non-existent keys
  • Error::SectionNotFound - Returned when accessing non-existent sections

Advanced Usage

Working with Arrays

use 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()?);
}

Error Handling

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);
    }
    _ => {}
}

Type Conversion

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"

Building

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

Requirements

  • Rust 1.56.0 or later (2021 edition)
  • No additional system dependencies

Performance

YINI-RS is designed for speed and efficiency:

  • Fast parsing: Optimized for large configuration files
  • Low memory usage: Minimal allocations during parsing
  • Zero-copy: String values reference the original input when possible

Benchmark results on a 1000-line configuration file:

  • Parse time: ~9ms
  • Write time: ~0.4ms

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Licensed under either of

at your option.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages