use std::cmp::Ordering; use std::fs::File; use std::io::{BufWriter, Write}; use e173::controller::{DmxDriver, ParamRange, ParameterCombo, ParameterConstraint}; use e173::schema::E173Document; use e173::schema::EstaDmx; use itertools::Itertools; fn main() { let doc: E173Document = serde_json::from_str(include_str!("data/martin_mac_encore_performance_cld.json")).unwrap(); let device_class = doc .e173doc .device_classes .get("com.martin.dev.encore-performance-cold") .unwrap() .get("1.0.0") .unwrap(); eprintln!("Deserialized UDR Document:"); eprintln!(" -- Author: {}", device_class.author); eprintln!(" -- Manufacturer: {}", device_class.info.manufacturer.name); eprintln!(" -- Model: {}", device_class.info.model.name); eprint!("\nParsing ESTA DMX serializer..."); let esta_dmx = serde_json::from_value::( device_class .serializers .get("dmx") .unwrap() .default .clone() .unwrap(), ) .unwrap(); eprintln!("Done."); eprint!("Transforming DMX data..."); let transformed = DmxDriver::from(&esta_dmx).unwrap(); eprintln!("Done."); println!("{}", serde_json::to_string_pretty(&transformed).unwrap()); to_html_output(&transformed, "export.html").unwrap(); } fn to_html_output(dmx_driver: &DmxDriver, file_name: &str) -> std::io::Result<()> { let mut out = BufWriter::new(File::create(file_name)?); out.write(b"\n")?; out.write(b"MAC Encore Performance - Standard")?; out.write( b"\n", )?; out.write(b"

DMX Combinations

")?; for cluster in &dmx_driver.clusters { let mut param_vec: Vec<_> = cluster.parameters.iter().collect(); param_vec.sort(); out.write(b"\n")?; out.write(b"")?; for parameter in ¶m_vec { out.write(format!("", parameter).as_bytes())?; } out.write(b"")?; let mut combinations = cluster.combinations.clone(); combinations.sort_by(compare_parameter_combo); for combination in combinations { out.write(b"\n")?; for parameter in ¶m_vec { out.write(b"")?; } out.write(b"")?; } out.write(b"
{}
")?; if let Some(constraint) = combination.constraints.get(*parameter) { out.write(range_to_html(&constraint.param_range).as_bytes())?; if let Some(mapping) = &constraint.dmx_mapping { let offsets = &dmx_driver.chunks.get(&mapping.chunk_id).unwrap().offsets; out.write(b"
Ch ")?; out.write( offsets .iter() .map(|offset| (offset + 1).to_string()) .join("+") .as_bytes(), )?; out.write(format!(": {}", mapping.start).as_bytes())?; if mapping.end != mapping.start { out.write(format!(" > {}", mapping.end).as_bytes())?; } out.write(b"")?; } if constraint.calculated { out.write(b"
calculated")?; } } out.write(b"
")?; } out.write(b"")?; out.flush() } fn compare_parameter_combo(lhs: &ParameterCombo, rhs: &ParameterCombo) -> Ordering { if lhs.constraints.len() != rhs.constraints.len() { return lhs.constraints.len().cmp(&rhs.constraints.len()); } let mut lhs_constraints: Vec<_> = lhs.constraints.iter().collect(); let mut rhs_constraints: Vec<_> = rhs.constraints.iter().collect(); lhs_constraints.sort_by(compare_constraint); rhs_constraints.sort_by(compare_constraint); let mismatch = lhs_constraints .into_iter() .zip(rhs_constraints.into_iter()) .find(|(lhs, rhs)| lhs != rhs); match mismatch { None => Ordering::Equal, Some((lhs, rhs)) => compare_constraint(&lhs, &rhs), } } fn compare_constraint( lhs: &(&String, &ParameterConstraint), rhs: &(&String, &ParameterConstraint), ) -> Ordering { lhs.0.cmp(&rhs.0).then( lhs.1 .param_range .partial_cmp(&rhs.1.param_range) .unwrap_or(Ordering::Equal), ) } fn range_to_html(range: &ParamRange) -> String { match range { ParamRange::Null => "".into(), ParamRange::Bool { start, end } => { if start != end { format!("{start} > {end}") } else { format!("{start}") } } ParamRange::Numeric { start, end } => { if start != end { format!("{start} > {end}") } else { format!("{start}") } } } }