pub mod anim;
pub mod csg;
pub mod error;
pub mod generators;
pub mod gltf;
pub mod mesh;
pub mod noise;
pub mod palette;
pub mod recipe;
pub mod render;
pub mod sdf;
pub mod skinning;
pub mod subdiv;
pub mod texture;
pub mod uv;
pub mod validate;
pub mod world;
pub use error::{Error, Result};
pub use gltf::{Asset, to_glb};
pub use recipe::Recipe;
pub fn compile(recipe_json: &str) -> Result<Asset> {
let recipe = Recipe::parse(recipe_json).map_err(Error::Parse)?;
recipe.build().map_err(Error::Build)
}
pub fn compile_to_glb(recipe_json: &str) -> Result<Vec<u8>> {
Ok(to_glb(&compile(recipe_json)?))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn malformed_json_is_a_parse_error_not_a_panic() {
assert!(matches!(compile("}{ not json"), Err(Error::Parse(_))));
}
#[test]
fn invalid_recipe_is_a_build_error_not_a_panic() {
assert!(matches!(
compile(r#"{"kind":"tree","palette":"does-not-exist"}"#),
Err(Error::Build(_))
));
}
#[test]
fn hostile_numeric_input_is_clamped_not_a_panic() {
for json in [
r#"{"kind":"tree","params":{"branches":100000000}}"#,
r#"{"kind":"terrain","params":{"size":-50}}"#,
r##"{"kind":"custom","parts":[{"nodes":[{"shape":"sphere","radius":1,"subdivide":50,"color":"#ffffff"}]}]}"##,
] {
let glb = compile_to_glb(json).expect("hostile-but-parseable recipe should compile");
assert_eq!(&glb[0..4], b"glTF");
}
}
#[test]
fn error_displays_and_is_std_error() {
let e = compile("nope").unwrap_err();
let _: &dyn std::error::Error = &e;
assert!(!e.to_string().is_empty());
}
}