///|
// Decode an exact CID prefix without treating the block data as part of the CID.
fn decode_block(bytes : Bytes, limits : Limits) -> (Block, Int) raise CarError {
  let reader = match @cid.WireReader::new(bytes, cid_limits(limits)) {
    Ok(reader) => reader
    Err(err) => raise InvalidCid(err.to_string())
  }
  let first = match reader.read_varint("CID version or multihash") {
    Ok(n) => n
    Err(err) => raise InvalidCid(err.to_string())
  }
  match first {
    18UL => { // CIDv0 is exactly the sha2-256 multihash.
      let length = match reader.read_varint("CIDv0 digest length") {
        Ok(n) => n
        Err(err) => raise InvalidCid(err.to_string())
      }
      if length != 32UL {
        raise InvalidCid("CIDv0 digest must have 32 bytes")
      }
      match reader.read_fixed("CIDv0 digest", 32) {
        Ok(_) => ()
        Err(err) => raise InvalidCid(err.to_string())
      }
    }
    1UL => {
      // MoonLoom handles varint canonicality and bounds.
      for name in ["CID codec", "multihash code"] {
        match reader.read_varint(name) {
          Ok(_) => ()
          Err(err) => raise InvalidCid(err.to_string())
        }
      }
      let length = match reader.read_varint("digest length") {
        Ok(n) => bounded_length(n, 1024, "CID digest")
        Err(err) => raise InvalidCid(err.to_string())
      }
      match reader.read_fixed("digest", length) {
        Ok(_) => ()
        Err(err) => raise InvalidCid(err.to_string())
      }
    }
    _ => raise InvalidCid("unsupported CID version")
  }
  let cid_length = reader.position()
  let cid = checked_cid(bytes[:cid_length], limits)
  (Block::new(cid, bytes[cid_length:].to_owned()), cid_length)
}

///|
/// Encode a single CAR block section; this does not assert hash validity.
pub fn Block::encode(
  self : Block,
  limits? : Limits = Limits::default(),
) -> Bytes raise CarError {
  let cid = self.cid.to_bytes()
  ignore(checked_cid(cid, limits))
  if self.data.length() > limits.max_block - cid.length() {
    raise LimitExceeded(
      "block",
      limits.max_block.to_uint64(),
      cid.length().to_uint64() + self.data.length().to_uint64(),
    )
  }
  let n = cid.length() + self.data.length()
  @cid.encode_u64(n.to_uint64()) + cid + self.data
}