///|
/// Length of one standard (unpacked) Cap'n Proto frame at `offset`.
/// Returns `None` when more input is needed. Limits are checked from the
/// header before waiting for, or copying, the declared payload.
pub fn frame_length(
  input : Bytes,
  offset? : Int = 0,
  max_segments? : Int = 512,
  max_message_bytes? : Int = 64 * 1024 * 1024,
) -> Int? raise CapnpError {
  guard offset >= 0 && offset <= input.length() else {
    raise Bounds("frame offset is outside input")
  }
  guard max_segments > 0 && max_message_bytes >= 8 else {
    raise Limit("invalid frame limits")
  }
  if input.length() - offset < 4 {
    return None
  }
  let count = stream_u32(input, offset) + 1UL
  guard count <= max_segments.to_uint64() else {
    raise Limit("segment count exceeds the configured limit")
  }
  let header = (count + 2UL) / 2UL * 8UL
  guard header <= max_message_bytes.to_uint64() else {
    raise Limit("segment table exceeds the configured message limit")
  }
  if header > (input.length() - offset).to_uint64() {
    return None
  }
  let mut total = header
  for i in 0.. (input.length() - offset).to_uint64() {
    None
  } else {
    Some(total.to_int())
  }
}

///|
fn stream_u32(input : Bytes, offset : Int) -> UInt64 {
  let mut result = 0UL
  for i in 0..<4 {
    result = result | (input[offset + i].to_uint64() << (i * 8))
  }
  result
}