//! CAM artifact serialization. The engine owns freshness and posting gates. mod incremental; pub use incremental::artifact_cooperative; #[cfg(test)] use crate::IoError; use crate::Result; use solidcraft_cam::{JobInput, Toolpath, verify::Report}; pub fn escape(s: &str) -> String { s.replace('&', "&").replace('<', "<").replace('>', ">").replace('"', """).replace('\'', "'") } /// Synchronous compatibility wrapper; interactive clients use the cooperative entry point. pub fn artifact(input: &JobInput, path: &Toolpath, report: Option<&Report>, format: &str) -> Result { let mut future = std::pin::pin!(artifact_cooperative(input, path, report, format, || false, || std::future::ready(()))); loop { if let std::task::Poll::Ready(result) = std::future::Future::poll(future.as_mut(), &mut std::task::Context::from_waker(std::task::Waker::noop())) { return result; } } } // Original serializer retained only as an independent schema/escaping oracle in tests. #[cfg(test)] fn reference_artifact(input: &JobInput, path: &Toolpath, report: Option<&Report>, format: &str) -> Result { let json = |v: serde_json::Value| serde_json::to_string_pretty(&v).map_err(|e| IoError::Invalid(e.to_string())); match format { "toolpath" => json(serde_json::json!({"version":solidcraft_cam::VERSION,"input":input,"toolpath":path})), "validation" => json( serde_json::to_value(report.ok_or_else(|| IoError::Invalid("simulate first".into()))?).map_err(|e| IoError::Invalid(e.to_string()))?, ), "stock" => solidcraft_cam::verify::stock_stl(report.ok_or_else(|| IoError::Invalid("simulate first".into()))?, input.setup.stock.min.z) .map_err(|e| IoError::Invalid(e.to_string())), "setup_sheet" => { let mut html = format!( "{}

{}

Reference three-axis milling — not a qualified machine post.

Fingerprint: {}

Setup

{}

Operations

", escape(&input.setup.name), escape(&input.setup.name), escape(&path.fingerprint), escape(&serde_json::to_string_pretty(&input.setup).map_err(|e| IoError::Invalid(e.to_string()))?) ); for o in &input.operations { html.push_str(&format!( "", escape(&o.name), o.tool, o.feed, o.spindle, o.bottom )); } html.push_str("
NameToolFeed mm/minSpindle rpmBottom mm
{}{}{}{}{}

Tools

");
            html.push_str(&escape(&serde_json::to_string_pretty(&input.tools).map_err(|e| IoError::Invalid(e.to_string()))?));
            html.push_str("

Operation settings and selected geometry

");
            html.push_str(&escape(&serde_json::to_string_pretty(&input.operations).map_err(|e| IoError::Invalid(e.to_string()))?));
            html.push_str("
"); Ok(html) } _ => Err(IoError::Invalid("unknown CAM artifact format".into())), } }