///|
pub suberror WriteError {
InvalidDocument(String)
} derive(Debug)
///|
/// Canonical escaped KV1 text. All keys and strings are quoted; order and
/// duplicates are retained. Comments and original whitespace are not retained.
pub fn stringify(document : Document) -> String raise WriteError {
let builder = StringBuilder()
write_entries(builder, document.entries, 0)
builder.to_string()
}
///|
fn write_quoted(
builder : StringBuilder,
text : String,
) -> Unit raise WriteError {
builder.write_char('"')
for c in text {
match c {
'"' => builder.write_string("\\\"")
'\\' => builder.write_string("\\\\")
'\n' => builder.write_string("\\n")
'\r' => builder.write_string("\\r")
'\t' => builder.write_string("\\t")
_ => {
if c.to_int() == 0 {
raise InvalidDocument("NUL cannot be serialized as KV1 text")
}
builder.write_char(c)
}
}
}
builder.write_char('"')
}
///|
fn write_indent(builder : StringBuilder, depth : Int) -> Unit {
for _ in 0.. Unit raise WriteError {
if depth > 128 {
raise InvalidDocument("Object exceeds writer depth limit of 128")
}
for entry in entries {
if depth == 0 &&
(
entry.key.equal_ignore_ascii_case("#include") ||
entry.key.equal_ignore_ascii_case("#base")
) {
raise InvalidDocument(
"Directive keys cannot be serialized as ordinary entries",
)
}
write_indent(builder, depth)
write_quoted(builder, entry.key)
match entry.value {
Text(text) => {
builder.write_string(" ")
write_quoted(builder, text)
builder.write_string("\n")
}
Object(children) => {
builder.write_string("\n")
write_indent(builder, depth)
builder.write_string("{\n")
write_entries(builder, children, depth + 1)
write_indent(builder, depth)
builder.write_string("}\n")
}
}
}
}