use crate::format::RlxFile;
use anyhow::Result;
use rlx_pkg::{BakeWeight, ContainerKind, WriteOptions, infer_container, package_from_bake};
use std::path::Path;
pub fn write_rlxp(
path: impl AsRef<Path>,
file: &RlxFile,
container: Option<ContainerKind>,
) -> Result<()> {
let path = path.as_ref();
let container = infer_container(path, container)?;
let mut file = file.clone();
if file.weights.iter().all(|w| w.data.is_empty()) && file.needs_materialize() {
file.materialize_weights()?;
}
let weights: Vec<BakeWeight> = file
.weights
.iter()
.filter(|w| !w.data.is_empty())
.map(|w| BakeWeight {
name: w.name.clone(),
shape: w.shape.clone(),
encoding: w.encoding.clone(),
data: w.data.clone(),
})
.collect();
let weights = if weights.is_empty() {
harvest_constant_weights(&file)
} else {
weights
};
let opts = WriteOptions {
name: file.meta.name.clone(),
producer: Some("rlx-bake".into()),
container,
strip_graph_weights: true,
..WriteOptions::default()
};
package_from_bake(path, &file.graph, &weights, opts)
}
fn harvest_constant_weights(file: &RlxFile) -> Vec<BakeWeight> {
use rlx_ir::Op;
let mut out = Vec::new();
for n in file.graph.nodes() {
let Some(name) = n.name.as_deref() else {
continue;
};
if let Op::Constant { data } = &n.op {
if data.is_empty() {
continue;
}
let shape: Vec<usize> = n
.shape
.dims()
.iter()
.map(|d| match d {
rlx_ir::Dim::Static(x) => *x,
rlx_ir::Dim::Dynamic(_) => 0,
})
.collect();
out.push(BakeWeight {
name: name.to_string(),
shape,
encoding: "f32".into(),
data: data.clone(),
});
}
}
out
}
pub fn convert_rlx_to_rlxp(
input: impl AsRef<Path>,
output: impl AsRef<Path>,
container: Option<ContainerKind>,
) -> Result<()> {
let file = crate::format::read_rlx(input)?;
write_rlxp(output, &file, container)
}