///|
/// Portable benchmark and regression fixtures without wall-clock dependence.
pub(all) struct BenchmarkCase {
name : String
inputs : Array[String]
context : String
platform : String
expected_status : DispatchStatus
repetitions : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct BenchmarkResult {
name : String
operations : Int
matched : Int
prefixes : Int
misses : Int
mismatches : Int
score : Int
notes : Array[String]
} derive(Eq, @debug.Debug)
///|
pub(all) struct ComplexityReport {
bindings : Int
contexts : Int
findings : Int
parse_complexity : String
analysis_complexity : String
dispatch_complexity : String
memory_notes : Array[String]
} derive(Eq, @debug.Debug)
///|
pub fn benchmark_case(
name : String,
inputs : Array[String],
context? : String = "global",
platform? : String = "all",
expected_status? : DispatchStatus = Matched,
repetitions? : Int = 1,
) -> BenchmarkCase {
{
name,
inputs,
context,
platform,
expected_status,
repetitions: if repetitions < 1 {
1
} else {
repetitions
},
}
}
///|
/// Run a deterministic benchmark fixture and report semantic mismatches.
pub fn run_benchmark(
keymap : Keymap,
fixture : BenchmarkCase,
) -> BenchmarkResult {
let mut operations = 0
let mut matched = 0
let mut prefixes = 0
let mut misses = 0
let mut mismatches = 0
for _ in 0.. matched += 1
Prefix => prefixes += 1
_ => misses += 1
}
if result.status != fixture.expected_status {
mismatches += 1
}
}
}
let score = if operations == 0 {
100
} else {
100 - mismatches * 100 / operations
}
let notes : Array[String] = []
if mismatches > 0 {
notes.push("fixture expectation differs from dispatcher output")
}
if prefixes > 0 {
notes.push("prefix states require a timeout-aware UI dispatcher")
}
{
name: fixture.name,
operations,
matched,
prefixes,
misses,
mismatches,
score,
notes,
}
}
///|
pub fn benchmark_suite(
keymap : Keymap,
fixtures : Array[BenchmarkCase],
) -> Array[BenchmarkResult] {
let result : Array[BenchmarkResult] = []
for fixture in fixtures {
result.push(run_benchmark(keymap, fixture))
}
result
}
///|
pub fn benchmark_result_to_json(result : BenchmarkResult) -> String {
let notes : Array[String] = []
for note in result.notes {
notes.push(json_string(note))
}
"{\"name\":" +
json_string(result.name) +
",\"operations\":" +
result.operations.to_string() +
",\"matched\":" +
result.matched.to_string() +
",\"prefixes\":" +
result.prefixes.to_string() +
",\"misses\":" +
result.misses.to_string() +
",\"mismatches\":" +
result.mismatches.to_string() +
",\"score\":" +
result.score.to_string() +
",\"notes\":[" +
notes.join(",") +
"]}"
}
///|
pub fn benchmark_results_to_markdown(
results : Array[BenchmarkResult],
) -> String {
let lines : Array[String] = [
"## Dispatcher benchmark", "", "| Fixture | Operations | Matched | Prefix | Misses | Mismatches | Score |",
"| --- | ---: | ---: | ---: | ---: | ---: | ---: |",
]
for result in results {
lines.push(
"| " +
result.name +
" | " +
result.operations.to_string() +
" | " +
result.matched.to_string() +
" | " +
result.prefixes.to_string() +
" | " +
result.misses.to_string() +
" | " +
result.mismatches.to_string() +
" | " +
result.score.to_string() +
" |",
)
}
lines.join("\n")
}
///|
/// Explain the current implementation's asymptotic behavior so it can be
/// tracked when a future indexed implementation is introduced.
pub fn complexity_report(
keymap : Keymap,
analysis : Analysis,
) -> ComplexityReport {
{
bindings: keymap.bindings.length(),
contexts: keymap.contexts.length(),
findings: analysis.findings.length(),
parse_complexity: "O(lines × attributes)",
analysis_complexity: "O(bindings² + bindings × context-depth)",
dispatch_complexity: "O(bindings × context-depth)",
memory_notes: [
"parser stores one owned string per attribute", "analysis retains findings for review and CI annotations",
"conflict graph adds one edge per pair finding",
],
}
}
///|
pub fn complexity_to_markdown(report : ComplexityReport) -> String {
let lines : Array[String] = [
"## Complexity profile",
"",
"- bindings: " + report.bindings.to_string(),
"- contexts: " + report.contexts.to_string(),
"- findings: " + report.findings.to_string(),
"- parser: `" + report.parse_complexity + "`",
"- analysis: `" + report.analysis_complexity + "`",
"- dispatch: `" + report.dispatch_complexity + "`",
"",
"### Memory notes",
]
for note in report.memory_notes {
lines.push("- " + note)
}
lines.join("\n")
}