API Reference
Rust API reference for the zoko-parser crate
The zoko-parser crate provides a Rust API for parsing and manipulating Zoko files.
Installation
Add to your Cargo.toml:
[dependencies]
zoko-parser = "0.2"Core Functions
parse_zoko
Parse a Zoko string into a ZokoFile structure.
use zoko_parser::parse_zoko;
fn main() {
let zoko_content = r#"
name: "My Application",
version: "1.0.0",
debug: true,
"#;
match parse_zoko(zoko_content) {
Ok(zoko_file) => {
println!("Parsed {} entries", zoko_file.entries.len());
}
Err(e) => {
eprintln!("Parse error: {}", e);
}
}
}Signature:
pub fn parse_zoko(input: &str) -> Result<ZokoFile, ParseErrorKind>Parameters:
input: A string slice containing Zoko content
Returns:
Ok(ZokoFile): Successfully parsed Zoko fileErr(ParseErrorKind): Parse error with details
parse_zoko_to_json
Parse a Zoko string and convert it to a JSON string.
use zoko_parser::parse_zoko_to_json;
fn main() {
let zoko_content = r#"
name: "My Application",
version: "1.0.0",
"#;
match parse_zoko_to_json(zoko_content) {
Ok(json) => {
println!("{}", json);
}
Err(e) => {
eprintln!("Conversion error: {}", e);
}
}
}Signature:
pub fn parse_zoko_to_json(input: &str) -> Result<String, ParseErrorKind>Parameters:
input: A string slice containing Zoko content
Returns:
Ok(String): JSON string representationErr(ParseErrorKind): Parse error with details
parse_zoko_with_includes
Parse a Zoko string with support for file includes.
use zoko_parser::parse_zoko_with_includes;
use std::path::Path;
fn main() {
let zoko_content = r#"
@include("common.zo"),
app_name: "MyApp",
"#;
let base_path = Path::new("/path/to/config");
match parse_zoko_with_includes(zoko_content, base_path) {
Ok(zoko_file) => {
println!("Parsed {} entries", zoko_file.entries.len());
}
Err(e) => {
eprintln!("Parse error: {}", e);
}
}
}Signature:
pub fn parse_zoko_with_includes(input: &str, base_path: &Path) -> Result<ZokoFile, ParseErrorKind>Parameters:
input: A string slice containing Zoko contentbase_path: Base directory path for resolving relative include paths
Returns:
Ok(ZokoFile): Successfully parsed Zoko file with includes resolvedErr(ParseErrorKind): Parse error with details (including circular dependency detection)
Data Structures
ZokoFile
The main structure representing a parsed Zoko file.
pub struct ZokoFile {
pub entries: IndexMap<String, Value>,
}Fields:
entries: Ordered map of key-value pairs (uses IndexMap for order preservation)
Value
Enum representing all possible values in a Zoko file.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
String(String),
Integer(i64),
Float(f64),
Decimal(Decimal),
Boolean(bool),
Array(Vec<Value>),
Object(IndexMap<String, Value>),
Null,
Date(NaiveDate),
Time(NaiveTime),
Duration(Duration),
Binary(Vec<u8>),
}Variants:
String(String): Text dataInteger(i64): Whole numbersFloat(f64): Floating-point numbersDecimal(Decimal): High-precision decimal numbersBoolean(bool): True/false valuesArray(Vec<Value>): Ordered list of valuesObject(IndexMap<String, Value>): Key-value mappingsNull: Absence of valueDate(NaiveDate): Calendar dates (YYYY-MM-DD format)Time(NaiveTime): Times of day (HH:MM:SS format)Duration(Duration): Time periods (supports hours, minutes, seconds)Binary(Vec<u8>): Binary data (base64 encoded)
ParseErrorKind
Error type for parsing errors.
#[derive(Debug, Error)]
pub enum ParseErrorKind {
#[error("Unexpected character: {0}")]
UnexpectedChar(char),
#[error("Unexpected end of input")]
UnexpectedEof,
#[error("Invalid number format: {0}")]
InvalidNumber(String),
#[error("Invalid escape sequence: {0}")]
InvalidEscape(String),
#[error("Expected {expected}, found {found}")]
Expected { expected: String, found: String },
}Usage Examples
Reading and Parsing a File
use std::fs;
use zoko_parser::parse_zoko;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = fs::read_to_string("config.zo")?;
let zoko_file = parse_zoko(&content)?;
println!("Parsed {} entries", zoko_file.entries.len());
Ok(())
}Accessing Parsed Values
use zoko_parser::parse_zoko;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
name: "My App",
version: "1.0.0",
debug: true,
"#;
let zoko_file = parse_zoko(content)?;
// Access values
if let Some(Value::String(name)) = zoko_file.entries.get("name") {
println!("Application name: {}", name);
}
if let Some(Value::Boolean(debug)) = zoko_file.entries.get("debug") {
println!("Debug mode: {}", debug);
}
Ok(())
}Working with Nested Structures
use zoko_parser::parse_zoko;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
config: {
database: {
host: "localhost",
port: 5432,
},
},
"#;
let zoko_file = parse_zoko(content)?;
// Access nested values
if let Some(Value::Object(config)) = zoko_file.entries.get("config") {
if let Some(Value::Object(database)) = config.get("database") {
if let Some(Value::String(host)) = database.get("host") {
println!("Database host: {}", host);
}
}
}
Ok(())
}Working with Arrays
use zoko_parser::parse_zoko;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
tags: ["production", "api"],
servers: [
{host: "server1", port: 8080},
{host: "server2", port: 8080},
],
"#;
let zoko_file = parse_zoko(content)?;
// Access array values
if let Some(Value::Array(tags)) = zoko_file.entries.get("tags") {
for tag in tags {
if let Value::String(tag_str) = tag {
println!("Tag: {}", tag_str);
}
}
}
// Access array of objects
if let Some(Value::Array(servers)) = zoko_file.entries.get("servers") {
for server in servers {
if let Value::Object(server_obj) = server {
if let Some(Value::String(host)) = server_obj.get("host") {
println!("Server: {}", host);
}
}
}
}
Ok(())
}Converting to Custom Types
use serde::Deserialize;
use zoko_parser::{parse_zoko, Value};
#[derive(Debug, Deserialize)]
struct Config {
name: String,
version: String,
debug: bool,
}
impl TryFrom<zoko_parser::ZokoFile> for Config {
type Error = String;
fn try_from(zoko_file: zoko_parser::ZokoFile) -> Result<Self, Self::Error> {
// Convert ZokoFile to your custom type
let json = serde_json::to_string(&zoko_file)
.map_err(|e| e.to_string())?;
serde_json::from_str(&json)
.map_err(|e| e.to_string())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
name: "My App",
version: "1.0.0",
debug: true,
"#;
let zoko_file = parse_zoko(content)?;
let config: Config = zoko_file.try_into()?;
println!("Config: {:?}", config);
Ok(())
}Working with Advanced Data Types
use zoko_parser::parse_zoko;
use chrono::NaiveDate;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
release_date: date("2024-06-21"),
price: decimal("19.99"),
timeout: duration("30s"),
data: binary("SGVsbG8gV29ybGQ="),
"#;
let zoko_file = parse_zoko(content)?;
// Access date values
if let Some(Value::Date(date)) = zoko_file.entries.get("release_date") {
println!("Release date: {}", date.format("%Y-%m-%d"));
}
// Access decimal values (for high-precision arithmetic)
if let Some(Value::Decimal(price)) = zoko_file.entries.get("price") {
println!("Price: {}", price);
}
// Access duration values
if let Some(Value::Duration(timeout)) = zoko_file.entries.get("timeout") {
println!("Timeout: {:?}", timeout);
}
// Access binary values
if let Some(Value::Binary(data)) = zoko_file.entries.get("data") {
println!("Binary data length: {} bytes", data.len());
}
Ok(())
}Using File Includes
use zoko_parser::parse_zoko_with_includes;
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
@include("common/config.zo"),
@include("database/settings.zo"),
app_name: "MyApp",
debug: true,
"#;
let base_path = Path::new("/path/to/config");
let zoko_file = parse_zoko_with_includes(content, base_path)?;
println!("Parsed {} entries (including includes)", zoko_file.entries.len());
Ok(())
}Error Handling
use zoko_parser::{parse_zoko, ParseErrorKind};
fn main() {
let content = r#"
name: "My App",
version: 1.0.0, // Invalid: should be "1.0.0"
"#;
match parse_zoko(content) {
Ok(zoko_file) => {
println!("Successfully parsed");
}
Err(ParseErrorKind::InvalidNumber(num)) => {
eprintln!("Invalid number format: {}", num);
}
Err(ParseErrorKind::Expected { expected, found }) => {
eprintln!("Expected {}, found {}", expected, found);
}
Err(e) => {
eprintln!("Parse error: {}", e);
}
}
}Serialization
The ZokoFile and Value types implement Serialize and Deserialize from serde, making them compatible with JSON and other formats.
Serialize to JSON
use zoko_parser::parse_zoko;
use serde_json;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = r#"
name: "My App",
version: "1.0.0",
"#;
let zoko_file = parse_zoko(content)?;
let json = serde_json::to_string_pretty(&zoko_file)?;
println!("{}", json);
Ok(())
}Deserialize from JSON
use zoko_parser::ZokoFile;
use serde_json;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let json = r#"{
"entries": {
"name": "My App",
"version": "1.0.0"
}
}"#;
let zoko_file: ZokoFile = serde_json::from_str(json)?;
println!("Parsed {} entries", zoko_file.entries.len());
Ok(())
}Performance Considerations
- Order Preservation: The use of
IndexMapensures order preservation but has slightly higher memory overhead thanHashMap - Parsing Speed: The parser uses nom combinators for efficient parsing
- Memory Usage: Large files are parsed entirely into memory; consider streaming for very large files
Thread Safety
The ZokoFile and Value types are Send and Sync when their contents are Send and Sync, making them safe to share across threads.
Integration with Other Crates
Use with Serde
use zoko_parser::{parse_zoko, Value};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct AppConfig {
#[serde(flatten)]
entries: IndexMap<String, Value>,
}Use with Clap
use clap::Parser;
use zoko_parser::parse_zoko;
#[derive(Parser)]
struct Cli {
#[arg(short, long)]
config: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
let content = std::fs::read_to_string(cli.config)?;
let zoko_file = parse_zoko(&content)?;
println!("Parsed configuration");
Ok(())
}2026 © All Rights Reserved.
- All the content is available under CC BY-SA 4.0, expect where otherwise stated.
- Source code is available on GitLab, licensed under Apache 2.0.
Last updated on
