///|
// Measure compact JSON without allocating escaped copies of long source labels.
fn string_json_units(text : String) -> Int64 {
let mut units = 2L
for i = 0; i < text.length(); i = i + 1 {
let ch = text[i]
units = units +
(match ch.to_int() {
8 | 9 | 10 | 12 | 13 | 34 | 92 => 2L
c if c < 32 => 6L
_ => 1L
})
}
units
}
///|
fn json_units(value : Json) -> Int64 {
match value {
String(s) => string_json_units(s)
Array(items) => {
let mut n = 2L
for i = 0; i < items.length(); i = i + 1 {
n = n + json_units(items[i]) + (if i == 0 { 0L } else { 1L })
}
n
}
Object(fields) => {
let mut n = 2L
let mut first = true
for key, value in fields {
n = n +
string_json_units(key) +
1L +
json_units(value) +
(if first { 0L } else { 1L })
first = false
}
n
}
_ => value.stringify().length().to_int64()
}
}
///|
priv struct OutputBudget {
maximum : Int64
mut used : Int64
}
///|
fn output_budget(maximum : Int64) -> OutputBudget raise InputError {
if maximum < 0L || maximum > 100000000L {
raise Rejected(
"output_limit", "output budget must be 0..100000000 UTF-16 units",
)
}
{ maximum, used: 0L, }
}
///|
fn OutputBudget::add(
self : OutputBudget,
units : Int64,
) -> Unit raise InputError {
if units < 0L || units > self.maximum - self.used {
raise Rejected(
"output_limit",
"rendered output exceeds \{self.maximum} UTF-16 units",
)
}
self.used = self.used + units
}
///|
fn safe_units(text : String) -> Int64 {
let mut units = 0L
for ch in text {
units = units +
(match ch {
'&' | '`' | '[' | ']' | '*' | '_' | '$' | '\\' => 5L
'<' | '>' => 4L
'|' | '~' => 6L
'\n' | '\r' | '\t' => 1L
_ =>
if ch.to_int() < 32 || (ch.to_int() >= 127 && ch.to_int() <= 159) {
0L
} else if ch.to_int() > 65535 {
2L
} else {
1L
}
})
}
units
}
///|
fn terminal_units(text : String) -> Int64 {
let mut units = 0L
for ch in text {
units = units +
(if ch.to_int() < 32 || (ch.to_int() >= 127 && ch.to_int() <= 159) {
6L
} else if ch.to_int() > 65535 {
2L
} else {
1L
})
}
units
}
///|
// Bounded diagnostic context, even when a shared suite name is very large.
fn TestId::preview(self : TestId) -> String {
match self {
Class(classname, name) =>
"class " + clipped(classname, 80) + "/" + clipped(name, 80)
SuitePath(path, name) => {
let parts : Array[String] = []
for part in path {
if parts.length() >= 3 {
break
}
parts.push(clipped(part, 48))
}
"suite " +
parts.join("/") +
(if path.length() > 3 { "/…" } else { "" }) +
"/" +
clipped(name, 80)
}
}
}
///|
fn clipped(text : String, limit : Int32) -> String {
if text.length() <= limit {
text
} else {
truncate_utf16(text, limit - 1) + "…"
}
}