rust-usd 0.0.4

Rust bindings to OpenUSD (pxr C++): stage open, prim/mesh attrs, variants, sublayer authoring, UsdShade read+write, ArResolver hook.
use std::env;
use std::fs;
use std::process;

use rust_usd::Stage;

const ASSET: &str = "examples/variants.usda";
const EDIT_LAYER: &str = "examples/paint_edits_variants.usda";
const PRIM_PATH: &str = "/Cube";
const VARIANT_SET: &str = "color";

fn main() {
    let target_variant = env::args().nth(1).unwrap_or_else(|| "green".to_string());

    // Start clean so the demo's behavior is deterministic across reruns.
    let _ = fs::remove_file(EDIT_LAYER);

    let asset_bytes_before = fs::read(ASSET).expect("variants.usda missing");

    print_variant_state("baseline (asset only)", ASSET);

    let stage = Stage::open_for_painting(ASSET, EDIT_LAYER).unwrap_or_else(|e| {
        eprintln!("open_for_painting failed: {}", e.what());
        process::exit(1);
    });

    println!(
        "edit target → {}",
        stage.edit_layer_path()
    );

    let prim = stage.prim_at_path(PRIM_PATH).unwrap_or_else(|| {
        eprintln!("prim {} not found", PRIM_PATH);
        process::exit(1);
    });

    let vset = prim.variant_set(VARIANT_SET).unwrap_or_else(|| {
        eprintln!("variant set {} not found on {}", VARIANT_SET, PRIM_PATH);
        process::exit(1);
    });

    println!("variants on {}: {:?}", PRIM_PATH, vset.variants());
    println!("composed selection (before set): {:?}", vset.selection());

    if !vset.set_selection(&target_variant) {
        eprintln!("set_selection({:?}) failed — variant doesn't exist", target_variant);
        process::exit(1);
    }
    println!(
        "composed selection (after set): {:?} (authored locally: {})",
        vset.selection(),
        vset.has_authored_selection()
    );

    stage.save_edit_layer();
    println!("saved edit layer to {}", EDIT_LAYER);

    print_variant_state("re-opened edit layer", EDIT_LAYER);

    let asset_bytes_after = fs::read(ASSET).expect("variants.usda gone");
    if asset_bytes_before == asset_bytes_after {
        println!("verified {} is byte-identical to its original", ASSET);
    } else {
        eprintln!("ASSET WAS MUTATED — this should never happen");
        process::exit(2);
    }
}

fn print_variant_state(tag: &str, path: &str) {
    let stage = Stage::open(path).unwrap_or_else(|e| {
        eprintln!("[{tag}] failed to open {path}: {}", e.what());
        process::exit(1);
    });
    let Some(prim) = stage.prim_at_path(PRIM_PATH) else {
        println!("[{tag}] no prim at {PRIM_PATH}");
        return;
    };
    let Some(vset) = prim.variant_set(VARIANT_SET) else {
        println!("[{tag}] no variant set {VARIANT_SET}");
        return;
    };
    println!(
        "[{tag}] selection={:?} authored_locally={}",
        vset.selection(),
        vset.has_authored_selection()
    );
}