///|
fn[A : Eq] IdMap::write(
  self : IdMap[A],
  writer : UpdateWriter,
  encode_value : (A) -> Any,
) -> Unit {
  let clients = self.clients.to_array()
  clients.sort_by(fn(a, b) { a.0.compare(b.0) })
  writer.raw.uint(clients.length().to_uint64())
  let attributes : Array[ContentAttribute[A]] = []
  let names : Array[String] = []
  let mut previous_client = 0UL
  for (client, ranges) in clients {
    writer.raw.uint(client - previous_client)
    previous_client = client
    writer.raw.uint(ranges.length().to_uint64())
    let mut previous_end = 0U
    for range in ranges {
      writer.raw.uint(
        (range.start - (if writer.v2 { previous_end } else { 0U })).to_uint64(),
      )
      writer.raw.uint(
        (range.end - range.start - (if writer.v2 { 1U } else { 0U })).to_uint64(),
      )
      previous_end = range.end
      writer.raw.uint(range.attrs.length().to_uint64())
      for attr in range.attrs.values {
        let mut index = 0
        while index < attributes.length() && attributes[index] != attr {
          index += 1
        }
        writer.raw.uint(index.to_uint64())
        if index == attributes.length() {
          attributes.push(attr)
          let mut name_index = 0
          while name_index < names.length() && names[name_index] != attr.name {
            name_index += 1
          }
          writer.raw.uint(name_index.to_uint64())
          if name_index == names.length() {
            names.push(attr.name)
            writer.string(attr.name)
          }
          writer.raw.any(encode_value(attr.value))
        }
      }
    }
  }
}

///|
pub fn[A : Eq] IdMap::encode_v1(
  self : IdMap[A],
  encode_value : (A) -> Any,
) -> Bytes {
  let writer = UpdateWriter::make(false)
  self.write(writer, encode_value)
  writer.raw.finish()
}

///|
pub fn[A : Eq] IdMap::encode_v2(
  self : IdMap[A],
  encode_value : (A) -> Any,
) -> Bytes raise DecodeError {
  let writer = UpdateWriter::make(true)
  self.write(writer, encode_value)
  writer.finish()
}

///|
fn[A] IdMap::read(
  reader : UpdateReader,
  decode_value : (Any) -> A raise DecodeError,
) -> IdMap[A] raise DecodeError {
  let result = IdMap()
  let attrs : Array[ContentAttribute[A]] = []
  let names : Array[String] = []
  let mut previous_client = 0UL
  for _ in 0..= previous_end &&
        start + length <= 0xffff_ffffUL &&
        length > 0UL else {
        raise InvalidData("invalid attribution range")
      }
      let values = []
      for _ in 0.. A raise DecodeError,
  max_items~ : Int32 = 1000000,
) -> IdMap[A] raise DecodeError {
  let reader = UpdateReader::make(bytes, false, max_items)
  let result = IdMap::read(reader, decode_value)
  reader.finish()
  result
}

///|
pub fn[A] IdMap::decode_v2(
  bytes : Bytes,
  decode_value : (Any) -> A raise DecodeError,
  max_items~ : Int32 = 1000000,
) -> IdMap[A] raise DecodeError {
  let reader = UpdateReader::make(bytes, true, max_items)
  let result = IdMap::read(reader, decode_value)
  reader.finish()
  result
}