///|
fn append_section(out : StringBuilder, title : String, body : String) -> Unit {
out.write_string("\n## ")
out.write_string(title)
out.write_char('\n')
out.write_string(body)
if !body.has_suffix("\n") {
out.write_char('\n')
}
}
///|
fn append_result_section(
out : StringBuilder,
title : String,
result : Result[String, PackError],
) -> Unit {
match result {
Ok(body) => append_section(out, title, body)
Err(err) => append_section(out, title, error_message(err))
}
}
///|
fn density_report_for_layout(layout : Layout) -> Result[String, PackError] {
let cell_w = (layout.bin.width / 8).max(1)
let cell_h = (layout.bin.height / 8).max(1)
match density_grid(layout, cell_width=cell_w, cell_height=cell_h) {
Err(err) => Err(err)
Ok(report) => Ok(to_density_report(report))
}
}
///|
fn constraint_report_for_layout(layout : Layout) -> Result[String, PackError] {
match check_constraints(layout, LayoutConstraints::strict()) {
Err(err) => Err(err)
Ok(violations) => Ok(to_constraint_report(violations))
}
}
///|
/// Build a complete text audit for a validated layout.
pub fn full_layout_audit(layout : Layout) -> Result[String, PackError] {
match validate_layout(layout) {
Err(err) => Err(err)
Ok(_) => {
let out = StringBuilder()
out.write_string("rectloom full layout audit\n")
out.write_string("signature=")
match layout_signature(layout) {
Ok(signature) => out.write_string(signature)
Err(err) => out.write_string(error_message(err))
}
out.write_char('\n')
append_section(out, "layout", to_report(layout))
append_result_section(out, "statistics", to_analysis_report(layout))
append_result_section(out, "diagnostics", diagnose_layout_report(layout))
append_result_section(
out,
"constraints",
constraint_report_for_layout(layout),
)
append_result_section(out, "density", density_report_for_layout(layout))
Ok(out.to_string())
}
}
}
///|
/// Parse, pack, and audit a text spec in one call.
pub fn audit_spec(source : String) -> Result[String, PackError] {
match pack_spec(source) {
Err(err) => Err(err)
Ok(layout) => full_layout_audit(layout)
}
}
///|
fn append_source_summary(
out : StringBuilder,
rects : ArrayView[Rect],
options : PackOptions,
) -> Unit {
append_section(
out,
"source",
to_rect_stats_report(summarize_rects_for_bin(rects, options.bin)),
)
append_section(
out,
"source-diagnostics",
to_diagnostics_report(diagnose_rects_for_bin(rects, options.bin)),
)
}
///|
/// Pack, compare option variants, and return a combined audit report.
pub fn packing_audit(
rects : ArrayView[Rect],
options : PackOptions,
) -> Result[String, PackError] {
match compare_packers(rects, options) {
Err(err) => Err(err)
Ok(comparison) => {
let out = StringBuilder()
out.write_string("rectloom packing audit\n")
append_source_summary(out, rects, options)
append_section(out, "comparison", to_comparison_report(comparison))
append_section(out, "best-layout", to_report(comparison.best.layout))
append_result_section(
out,
"best-statistics",
to_analysis_report(comparison.best.layout),
)
append_result_section(
out,
"best-diagnostics",
diagnose_layout_report(comparison.best.layout),
)
Ok(out.to_string())
}
}
}
///|
/// Run a complete audit against a built-in fixture family.
pub fn fixture_audit(
kind : FixtureKind,
count : Int,
) -> Result[String, PackError] {
let rects = fixture_rects(kind, count)
let options = fixture_options(kind)
match packing_audit(rects, options) {
Err(err) => Err(err)
Ok(report) => {
let out = StringBuilder()
out.write_string("fixture=")
out.write_string(fixture_name(kind))
out.write_char('\n')
out.write_string("description=")
out.write_string(fixture_description(kind))
out.write_char('\n')
out.write_string(report)
Ok(out.to_string())
}
}
}
///|
/// Produce a compact one-screen summary for command line demos.
pub fn compact_audit_summary(layout : Layout) -> Result[String, PackError] {
match analyze_layout(layout) {
Err(err) => Err(err)
Ok(stats) => {
let out = StringBuilder()
out.write_string("algorithm=")
out.write_string(algorithm_name(layout.algorithm))
out.write_string(" placed=")
out.write_string("\{stats.placed_count}")
out.write_string(" unpacked=")
out.write_string("\{stats.unpacked_count}")
out.write_string(" occupancy=")
out.write_string("\{stats.occupancy_permille}/1000")
out.write_string(" compactness=")
out.write_string("\{stats.compactness_score}/1000")
out.write_string(" fragmentation=")
out.write_string("\{stats.fragmentation_score}/1000")
Ok(out.to_string())
}
}
}