// A length-prefixed frame, which is the shape most protocols send: a varint
// holding the payload's length, then the payload. The length's own width is not
// known until the payload is, which is what `quic.size` is for.
//
//     moon run src/examples/frame

///|
#coverage.skip
fn main {
  let payload = b"\x01\x02\x03\x04\x05"[:]
  let framed = frame(payload)
  println("framed      \{hex(framed[:])}")
  println("length      \{@quic.decode(framed[:]).unwrap().0}")
  println("payload     \{hex(unframe(framed[:]).unwrap()[:])}")
  // A payload long enough that its length no longer fits in one octet: the
  // same two lines, with a wider number in front.
  let big = Bytes::make(300, b'\x2a')
  let wide = frame(big[:])
  println("300 octets  \{hex(wide[:3])} ... (\{wide.length()} octets in all)")
  println("round trip  \{unframe(wide[:]).unwrap().length() == 300}")
  // A frame that claims more than it carries is refused, not half-read.
  println("refused     \{unframe(b"\x05\x01\x02"[:]) is None}")
}

///|
/// `payload` with its length in front, as QUIC writes a length.
fn frame(payload : BytesView) -> Bytes {
  let buf = Buffer()
  // The length is itself a QUIC varint, so a short payload costs one octet.
  buf.write_bytes(@quic.encode(payload.length().to_uint64()))
  buf.write_bytes(payload.to_owned())
  buf.to_bytes()
}

///|
/// The payload of `b`, or `None` when the frame claims more than it carries.
fn unframe(b : BytesView) -> Bytes? {
  match @quic.decode(b) {
    Some((len, taken)) =>
      if b.length() - taken >= len.to_int() {
        Some(b[taken:taken + len.to_int()].to_owned())
      } else {
        None
      }
    None => None
  }
}

///|
/// Octets as hex, two digits each.
fn hex(b : BytesView) -> String {
  let digits = "0123456789abcdef"
  let out = StringBuilder()
  for i = 0; i < b.length(); i = i + 1 {
    let octet = b[i].to_int()
    out.write_char(digits[octet >> 4].unsafe_to_char())
    out.write_char(digits[octet & 0xf].unsafe_to_char())
  }
  out.to_string()
}