oslquery-petite 0.1.0

Query Open Shading Language (OSL) shader parameters & metadata
Documentation

oslquery-petite

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

Overview

oslquery-petite provides a pure Rust implementation compatible with OpenShadingLanguage's liboslquery. This is designed for integration with 3D rendering pipelines. It 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.
  • Support for all OSL base types (int, float, string, color, point, vector, normal, matrix).
  • Handle arrays (fixed and variable-length).
  • Parse default values for all parameter types.
  • Extract metadata hints and attributes.
  • Support for closure types.
  • Compatible with 3Delight, Cycles, and other OSL implementations.
  • Optional oslq (like oslinfo) CLI tool for querying shaders.

Installation

Add to your Cargo.toml:

[dependencies]
oslquery-petite = "0.1"

With optional features:

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

Features

  • cli - Enables the oslq command-line tool.
  • json - Enables JSON serialization support.
  • hash - Derives Hash for all public types.

Quick Start

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:

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

With this API, it's impossible to have type mismatches - a Color parameter always has exactly 3 floats, a Matrix always has 16, and you can't accidentally mix types.

API Overview

OslQuery

The main entry point for querying shader information:

// 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:

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:

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

# 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

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

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

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.