///|
/// Serving part of a file (RFC 9110 §14): reading the `Range` a player sends,
/// measuring it against the length, and writing the `Content-Range` that goes
/// back — including the 416 answer, which says how long the file actually is.
///
///     moon run src/examples/12-range --target native
#coverage.skip
fn main {
  // A ten-thousand-octet representation, and the asks §14.1.2 prints.
  let length = 10000L
  println("Accept-Ranges: \{@range.accept()}")
  for
    asked in [
      "bytes=0-499", "bytes=-500", "bytes=9500-", "bytes=0-999, 4500-5499, -1000",
      "bytes=500-600,601-999", "bytes=20000-", "items=0-9",
    ] {
    let answer = match @range.decode(asked) {
      // §14.2: a unit we do not implement is ignored, and the answer is 200
      // with the whole representation.
      None => "ignored -> 200, the whole thing"
      Some(specs) =>
        match @range.measure(specs[:], length~) {
          // §14.4: a 416 still says how long the representation is, so the
          // client can ask again for something that exists.
          None => "416 -> " + @range.unsatisfied(length).encode()
          Some(parts) => {
            let lines = []
            for part in parts {
              lines.push(
                @range.Content::new(part, complete=length).encode() +
                " (\{part.length()} octets)",
              )
            }
            "206 -> " + lines.join("\n         ")
          }
        }
    }
    println(asked)
    println("  " + answer)
  }

  // More than one range travels as multipart/byteranges (§14.6).
  let head : @range.Part = { at: 0L, last: 3L, }
  let tail : @range.Part = { at: 6L, last: 9L, }
  println("")
  println("Content-Type: \{@range.multipart("cut")}")
  let body = @range.parts(
    [(head, b"0123"), (tail, b"6789")][:],
    boundary="cut",
    kind="text/plain",
    complete=10L,
  )
  let shown = StringBuilder()
  for byte in body {
    if byte == b'\r' {
      shown.write_string("\\r")
    } else if byte == b'\n' {
      shown.write_string("\\n\n")
    } else {
      shown.write_char(byte.to_int().unsafe_to_char())
    }
  }
  println(shown.to_string())
}