Expand description
§serini
A serde-based INI file parser that supports serialization and deserialization of Rust structs.
§Features
- Serialize Rust structs to INI format - Nested structs become sections
- Deserialize INI files to Rust structs - Type-safe parsing with automatic type conversion
- Option handling -
Nonevalues are serialized as commented lines - Escape sequences - Properly handles special characters in values
- Section support - Nested structs are automatically converted to INI sections
- Type safety - Leverages serde’s type system for safe conversions
§Quick Start
Add this to your Cargo.toml:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serini = "0.1"§Basic Example
use serde::{Deserialize, Serialize};
use serini::{from_str, to_string};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Config {
name: String,
port: u16,
#[serde(skip_serializing_if = "Option::is_none")]
debug: Option<usize>,
database: Database,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Database {
host: String,
port: u16,
username: String,
password: Option<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config {
name: "My Application".to_string(),
port: 8080,
debug: None,
database: Database {
host: "localhost".to_string(),
port: 5432,
username: "admin".to_string(),
password: None,
},
};
// Serialize to INI
let ini_string = to_string(&config)?;
println!("{}", ini_string);
// Output:
// name = My Application
// port = 8080
//
// [database]
// host = localhost
// port = 5432
// username = admin
// ; password =
// Deserialize from INI
let parsed: Config = from_str(&ini_string)?;
assert_eq!(config, parsed);
Ok(())
}§Section Handling
Nested structs automatically become INI sections:
use serde::{Deserialize, Serialize};
use serini::to_string;
#[derive(Serialize, Deserialize)]
struct ServerConfig {
general: General,
http: HttpConfig,
database: DatabaseConfig,
}
#[derive(Serialize, Deserialize)]
struct General {
name: String,
debug: bool,
}
#[derive(Serialize, Deserialize)]
struct HttpConfig {
host: String,
port: u16,
timeout: u64,
}
#[derive(Serialize, Deserialize)]
struct DatabaseConfig {
url: String,
max_connections: u32,
}
let config = ServerConfig {
general: General {
name: "MyServer".to_string(),
debug: false,
},
http: HttpConfig {
host: "0.0.0.0".to_string(),
port: 8080,
timeout: 30,
},
database: DatabaseConfig {
url: "postgres://localhost/mydb".to_string(),
max_connections: 100,
},
};
let ini = to_string(&config)?;Produces:
[general]
name = MyServer
debug = false
[http]
host = 0.0.0.0
port = 8080
timeout = 30
[database]
url = postgres://localhost/mydb
max_connections = 100§Option Handling
Option<T> fields are handled specially:
Some(value)is serialized normallyNoneis serialized as a commented line
use serde::{Deserialize, Serialize};
use serini::to_string;
#[derive(Serialize, Deserialize)]
struct User {
username: String,
email: Option<String>,
age: Option<u32>,
}
let user = User {
username: "alice".to_string(),
email: Some("alice@example.com".to_string()),
age: None,
};
let ini = to_string(&user)?;Produces:
username = alice
email = alice@example.com
; age =§Escape Sequences
Special characters in values are automatically escaped:
| Character | Escaped |
|---|---|
\ | \\ |
\n | \n |
\r | \r |
\t | \t |
" | \" |
; | \; |
# | \# |
use serde::{Deserialize, Serialize};
use serini::{from_str, to_string};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Message {
text: String,
note: String,
}
let msg = Message {
text: "Hello\nWorld!".to_string(),
note: "This has \"quotes\" and a ; semicolon".to_string(),
};
let ini = to_string(&msg)?;
// text = Hello\nWorld!
// note = This has \"quotes\" and a \; semicolon
let parsed: Message = from_str(&ini)?;
assert_eq!(msg, parsed);§Supported Types
The following types are supported for serialization and deserialization:
- Integers:
i8,i16,i32,i64,u8,u16,u32,u64 - Floats:
f32,f64 - Boolean:
bool(serialized astrue/false) - String:
String,&str - Option:
Option<T>whereTis a supported type - Structs: Custom structs with named fields
§Limitations
The following serde types are not supported:
- Sequences (Vec, arrays, etc.)
- Tuples and tuple structs
- Enums with variants
- Maps (HashMap, BTreeMap, etc.)
- Unit structs
Attempting to serialize or deserialize these types will result in an error.
§Error Handling
This crate uses anError type using thiserror to provide granular error variants:
use serde::{Deserialize, Serialize};
use serini::{from_str, Error};
#[derive(Deserialize)]
struct Config {
port: u16,
}
let ini = "port = not_a_number";
match from_str::<Config>(ini) {
Ok(_) => println!("Parsed successfully"),
Err(Error::InvalidValue { typ, value }) => {
println!("Invalid {} value: {}", typ, value);
}
Err(e) => println!("Error: {}", e),
}§API Reference
§Functions
§to_string
Serializes a value to an INI string.
§from_str
Deserializes an INI string to a value.
§Advanced Example
Here’s a complete example showing various features:
use serde::{Deserialize, Serialize};
use serini::{from_str, to_string};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct AppConfig {
#[serde(rename = "app-name")]
app_name: String,
version: String,
debug_mode: bool,
max_connections: u32,
timeout_seconds: Option<u64>,
server: ServerSettings,
database: DatabaseSettings,
cache: Option<CacheSettings>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct ServerSettings {
host: String,
port: u16,
#[serde(rename = "use-tls")]
use_tls: bool,
certificate_path: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct DatabaseSettings {
#[serde(rename = "connection-string")]
connection_string: String,
pool_size: u32,
timeout: u32,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct CacheSettings {
backend: String,
ttl_seconds: u64,
max_entries: u64,
}
// Create a configuration
let config = AppConfig {
app_name: "MyApp".to_string(),
version: "1.0.0".to_string(),
debug_mode: false,
max_connections: 100,
timeout_seconds: Some(30),
server: ServerSettings {
host: "0.0.0.0".to_string(),
port: 8443,
use_tls: true,
certificate_path: Some("/etc/ssl/cert.pem".to_string()),
},
database: DatabaseSettings {
connection_string: "postgres://user:pass@localhost/mydb".to_string(),
pool_size: 20,
timeout: 5,
},
cache: None,
};
// Serialize to INI
let ini_string = to_string(&config)?;
println!("Generated INI:\n{}", ini_string);
// Parse it back
let parsed: AppConfig = from_str(&ini_string)?;
assert_eq!(config, parsed);
// Example INI file that could be parsed
let ini_file = r#"
app-name = MyApp
version = 1.0.0
debug_mode = false
max_connections = 100
timeout_seconds = 30
[server]
host = 0.0.0.0
port = 8443
use-tls = true
certificate_path = /etc/ssl/cert.pem
[database]
connection-string = postgres://user:pass@localhost/mydb
pool_size = 20
timeout = 5
; cache =
"#;
let from_file: AppConfig = from_str(ini_file)?;
assert_eq!(config, from_file);§License
This project is licensed under the MIT License - see the LICENSE file for details.