oslquery-petite 0.1.1

Query Open Shading Language (OSL) shader parameters & metadata
Documentation
# `oslquery-petite`

A lightweight Rust crate for parsing and querying OSL (Open Shading Language) shader parameters & metadata from compiled `.oso` files.
Aims to match OSL's `liboslquery` in the feature subset it implements 1:1.

## Overview

`oslquery-petite` can parse OSO files generated by OSL compilers and extract shader parameters, types, default values, and metadata.

## Features

- Parse OSO files from OSL 1.00+ format.
- Extract shader parameters with complete type information.
- Compatible with 3Delight, Cycles, and other OSL implementations.
- `oslq` (like `oslinfo`) CLI tool for querying shaders.

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
oslquery-petite = "0.1"
```

With optional features:

```toml
[dependencies]
oslquery-petite = { version = "0.1", features = ["cli", "json", "hash"] }
```

### Features

- `json` - Enables JSON serialization support.
- `hash` - Derives `Hash` for all public types.

## Quick Start

```rust
use oslquery_petite::{OslQuery, TypedParameter};

// Parse an OSO file.
let query = OslQuery::open("shader.oso")?;

// Get shader information.
println!("Shader: {} ({})", query.shader_name(), query.shader_type());
println!("Parameters: {}", query.param_count());

// Iterate through parameters with type-safe access.
for param in query.params() {
    println!("  {}", param.name);
    match param.typed_param() {
        TypedParameter::Float { default } => {
            if let Some(val) = default {
                println!("    float = {}", val);
            }
        }
        TypedParameter::Color { default, .. } => {
            if let Some([r, g, b]) = default {
                println!("    color = [{}, {}, {}]", r, g, b);
            }
        }
        TypedParameter::String { default } => {
            if let Some(s) = default {
                println!("    string = \"{}\"", s);
            }
        }
        _ => {}
    }
}
```

## Type-Safe API

The API provides complete type safety where types and values are unified:

```rust
use oslquery_petite::{OslQuery, TypedParameter};

let query = OslQuery::open("shader.oso")?;
for param in query.params() {
    match param.typed_param() {
        TypedParameter::Color { default: Some([r, g, b]), .. } => {
            println!("Color: ({}, {}, {})", r, g, b);
        }
        TypedParameter::Float { default: Some(val) } => {
            println!("Float: {}", val);
        }
        TypedParameter::FloatArray { size, default: Some(vals) } => {
            println!("Float[{}]: {:?}", size, vals);
        }
        _ => {}
    }
}
```

The API prevents type mismatches – a `Color` parameter always has exactly 3 `float`s, a `Matrix` always has `16`. You can't accidentally mix types with different defaults.

## API Overview

### `OslQuery`

The main entry point for querying shader information:

```rust
// Parse from file.
let query = OslQuery::open("shader.oso")?;

// Parse from string.
let content = std::fs::read_to_string("shader.oso")?;
let query = OslQuery::from_string(&content)?;

// Query shader info.
let name = query.shader_name();        // e.g., "lambert"
let shader_type = query.shader_type(); // e.g., "surface"
let param_count = query.param_count();

// Access parameters.
let param = query.param_by_name("Kd"); // By name
let param = query.param_at(0);          // By index
let all_params = query.params();        // All parameters
```

### `Parameter`

Represents a shader parameter with type-safe access:

```rust
pub struct Parameter {
    pub name: Ustr,                   // Parameter name
    pub metadata: Vec<Metadata>,      // Metadata hints
    // Private fields encapsulate the typed parameter
}

impl Parameter {
    pub fn typed_param(&self) -> &TypedParameter;
    pub fn is_output(&self) -> bool;
    pub fn find_metadata(&self, name: &str) -> Option<&Metadata>;
}
```

### `TypedParameter`

Type-safe parameter representation where type and (default) value are unified:

```rust
pub enum TypedParameter {
    Int { default: Option<i32> },
    Float { default: Option<f32> },
    String { default: Option<String> },
    Color { default: Option<[f32; 3]>, space: Option<Ustr> },
    Point { default: Option<[f32; 3]>, space: Option<Ustr> },
    Vector { default: Option<[f32; 3]>, space: Option<Ustr> },
    Normal { default: Option<[f32; 3]>, space: Option<Ustr> },
    Matrix { default: Option<[f32; 16]> },
    IntArray { size: usize, default: Option<Vec<i32>> },
    FloatArray { size: usize, default: Option<Vec<f32>> },
    StringArray { size: usize, default: Option<Vec<String>> },
    // ... and dynamic arrays, closure types, etc.
}
```

## `oslq` – A Petite `oslinfo` Clone

```bash
# Query a shader.
oslq shader.oso

# Query multiple shaders/
oslq shader1.oso shader2.oso

# Query specific parameter.
oslq --param Kd shader.oso

# Use search path.
oslq -p /path/to/shaders:./local shader

# Verbose output.
oslq -v shader.oso

# JSON output (requires json feature).
oslq --json shader.oso

# Benchmark parsing.
oslq --runstats shader.oso
```

## Examples

### Parsing with Shader Search Path

```rust
use oslquery_petite::OslQuery;

// Search for shader.oso in multiple directories.
let searchpath = "/usr/local/shaders:/project/shaders";
let query = OslQuery::open_with_searchpath("shader", searchpath)?;
```

### Checking for Specific Metadata

```rust
use oslquery_petite::MetadataValue;

for param in query.params() {
    // Check for UI hints.
    if let Some(label) = param.find_metadata("label") {
        if let MetadataValue::String(s) = &label.value {
            println!("UI Label: {}", s);
        }
    }

    // Check for help text.
    if let Some(help) = param.find_metadata("help") {
        if let MetadataValue::String(s) = &help.value {
            println!("Help: {}", s);
        }
    }
}
```

### Arrays Handling

```rust
for param in query.params() {
    match param.typed_param() {
        TypedParameter::FloatArray { size, .. } => {
            println!("{} is a float array of size {}", param.name, size);
        }
        TypedParameter::FloatDynamicArray { .. } => {
            println!("{} is a variable-length float array", param.name);
        }
        TypedParameter::ColorArray { size, .. } => {
            println!("{} is a color array of size {}", param.name, size);
        }
        _ => {}
    }
}
```

## Differences from C++ `liboslquery`

While maintaining API compatibility where possible, this Rust implementation:

- Uses idiomatic Rust patterns (`Result` types, iterators, etc.).
- Supports incremental parsing.
- Has optional JSON serialization.
- Smaller binary size and faster compilation.

## License

Licensed under Apache-2.0 _or_ BSD-3-Clause _or_ MIT _or_ Zlib at your option.

## Contributing

Contributions are welcome! Please ensure:

- All tests pass with `cargo test`.
- Code is formatted with `cargo fmt`.
- No clippy warnings with `cargo clippy -- -W warnings`.
- Documentation is updated for API changes.

## Acknowledgments

Based on the OSL specification and inspired by with Open Shading Language's `liboslquery`/`oslinfo`.