// Packed repeated field encoding and decoding for protobuf.
// Reference: https://protobuf.dev/programming-guides/encoding/#packed

///|
/// Encode a packed repeated varint field (int32, uint32, sint32, bool, enum, int64, etc.)
pub fn encode_packed_varint(
  buf : Buffer,
  field_number : UInt,
  values : Array[UInt64],
) -> Unit {
  // First write all values to a temp buffer to compute length
  let temp = Buffer()
  for v in values {
    encode_varint(temp, v)
  }
  let data = temp.to_bytes()
  write_length_delimited_prefix(
    buf,
    field_number,
    data.length().reinterpret_as_uint(),
  )
  buf.write_bytes(data)
}

///|
/// Encode a packed repeated fixed32 field.
pub fn encode_packed_fixed32(
  buf : Buffer,
  field_number : UInt,
  values : Array[UInt],
) -> Unit {
  let len = values.length() * 4
  write_length_delimited_prefix(buf, field_number, len.reinterpret_as_uint())
  for v in values {
    write_fixed32(buf, v)
  }
}

///|
/// Encode a packed repeated fixed64 field.
pub fn encode_packed_fixed64(
  buf : Buffer,
  field_number : UInt,
  values : Array[UInt64],
) -> Unit {
  let len = values.length() * 8
  write_length_delimited_prefix(buf, field_number, len.reinterpret_as_uint())
  for v in values {
    write_fixed64(buf, v)
  }
}

///|
/// Encode a packed repeated float field.
pub fn encode_packed_float(
  buf : Buffer,
  field_number : UInt,
  values : Array[Float],
) -> Unit {
  let len = values.length() * 4
  write_length_delimited_prefix(buf, field_number, len.reinterpret_as_uint())
  for v in values {
    write_float(buf, v)
  }
}

///|
/// Encode a packed repeated double field.
pub fn encode_packed_double(
  buf : Buffer,
  field_number : UInt,
  values : Array[Double],
) -> Unit {
  let len = values.length() * 8
  write_length_delimited_prefix(buf, field_number, len.reinterpret_as_uint())
  for v in values {
    write_double(buf, v)
  }
}

///|
/// Decode all varints from packed bytes into an array.
pub fn decode_packed_varint(data : Bytes) -> Array[UInt64] {
  let mut pos = 0
  let result : Array[UInt64] = []
  while pos < data.length() {
    if decode_varint(data, pos) is Some((v, consumed)) {
      result.push(v)
      pos += consumed
    } else {
      break
    }
  }
  result
}

///|
/// Decode all fixed32 values from packed bytes into an array.
pub fn decode_packed_fixed32(data : Bytes) -> Array[UInt] {
  let mut pos = 0
  let result : Array[UInt] = []
  while pos + 4 <= data.length() {
    if read_fixed32(data, pos) is Some((v, new_pos)) {
      result.push(v)
      pos = new_pos
    } else {
      break
    }
  }
  result
}

///|
/// Decode all fixed64 values from packed bytes into an array.
pub fn decode_packed_fixed64(data : Bytes) -> Array[UInt64] {
  let mut pos = 0
  let result : Array[UInt64] = []
  while pos + 8 <= data.length() {
    if read_fixed64(data, pos) is Some((v, new_pos)) {
      result.push(v)
      pos = new_pos
    } else {
      break
    }
  }
  result
}