///|
/// QPACK field-section coding (RFC 9204 §4.5): a header list encodes through the
/// static table (indexed lines, static-name references, and full literals) both
/// raw and Huffman, and decodes back exactly. The Encoded Field Section Prefix
/// (§4.5.1) carrying the Required Insert Count and Base round-trips too.
///
/// moon run src/examples/28-qpack-field --target native
#coverage.skip
fn main {
run() catch {
e => println("qpack field error: \{e}")
}
}
///|
fn run() -> Unit raise {
let headers = [
@header.Header::of(":method", "GET"),
@header.Header::of(":path", "/index.html"),
@header.Header::of(":scheme", "https"),
@header.Header::of(":status", "200"),
@header.Header::of("x-custom-header", "custom-value"),
@header.Header::of("content-type", "application/json"),
]
let raw = @qpack.encode(headers, huffman=false)
let huff = @qpack.encode(headers, huffman=true)
println("field section: raw=\{raw.length()} huffman=\{huff.length()} bytes")
println("raw round-trip = \{@qpack.decode(raw) == headers}")
println("huffman round-trip = \{@qpack.decode(huff) == headers}")
println("empty section = \{hex(@qpack.encode([], huffman=false))}")
// Section prefix: Required Insert Count 4, Base 6 (RFC 9204 §4.5.1).
let sp = @qpack.prefix(4, 6, 128)
match @qpack.read_prefix(sp[:], 128, 4) {
Some((ric, base, consumed)) =>
println(
"prefix: encoded=\{hex(sp)} decoded ric=\{ric} base=\{base} consumed=\{consumed}",
)
None => println("bad prefix")
}
}
///|
fn hex(b : Bytes) -> String {
let digits = "0123456789abcdef"
let sb = StringBuilder()
for i = 0; i < b.length(); i = i + 1 {
let x = b[i].to_int()
sb.write_char(digits[x >> 4].unsafe_to_char())
sb.write_char(digits[x & 0xf].unsafe_to_char())
}
sb.to_string()
}