///|
priv struct GifWriter {
  bytes : Array[Byte]
}

///|
fn GifWriter::new() -> GifWriter {
  { bytes: [] }
}

///|
fn GifWriter::byte(self : GifWriter, value : Int) -> Unit {
  self.bytes.push(value.to_byte())
}

///|
fn GifWriter::u16(self : GifWriter, value : Int) -> Unit {
  self.byte(value & 0xff)
  self.byte((value >> 8) & 0xff)
}

///|
fn GifWriter::bytes(self : GifWriter, values : ArrayView[Byte]) -> Unit {
  for value in values {
    self.bytes.push(value)
  }
}

///|
fn GifWriter::finish(self : GifWriter) -> Bytes {
  Bytes::from_array(self.bytes[:])
}

///|
priv struct GifCursor {
  data : Bytes
  mut position : Int
}

///|
fn GifCursor::new(data : Bytes) -> GifCursor {
  { data, position: 0 }
}

///|
fn GifCursor::remaining(self : GifCursor) -> Int {
  self.data.length() - self.position
}

///|
fn GifCursor::byte(self : GifCursor, context~ : String) -> Byte raise GifError {
  if self.position >= self.data.length() {
    raise UnexpectedEnd(context~)
  }
  let value = self.data[self.position]
  self.position += 1
  value
}

///|
fn GifCursor::u16(self : GifCursor, context~ : String) -> Int raise GifError {
  let low = self.byte(context~).to_int()
  let high = self.byte(context~).to_int()
  low | (high << 8)
}

///|
fn GifCursor::take(
  self : GifCursor,
  length : Int,
  context~ : String,
) -> Bytes raise GifError {
  if length < 0 || self.position + length > self.data.length() {
    raise UnexpectedEnd(context~)
  }
  let result : Array[Byte] = []
  for i in 0.. Unit raise GifError {
  if length < 0 || self.position + length > self.data.length() {
    raise UnexpectedEnd(context~)
  }
  self.position += length
}

///|
fn read_sub_blocks(
  cursor : GifCursor,
  context~ : String,
) -> Bytes raise GifError {
  let payload : Array[Byte] = []
  let mut done = false
  while !done {
    let size = cursor.byte(context~).to_int()
    if size == 0 {
      done = true
    } else {
      if size > 255 {
        raise InvalidBlock(context~)
      }
      for _ in 0.. Unit {
  let mut offset = 0
  while offset < payload.length() {
    let remaining = payload.length() - offset
    let size = if remaining > 255 { 255 } else { remaining }
    writer.byte(size)
    for i in 0.. (Int, Int) {
  let mut bits = 1
  let mut size = 2
  while size < palette.len() && bits < 8 {
    bits += 1
    size = size << 1
  }
  (size, bits)
}

///|
fn write_palette(
  writer : GifWriter,
  palette : Palette,
  table_size : Int,
) -> Unit {
  for i in 0.. writer.bytes([0, 0, 0])
      Some(color) => writer.bytes([color.red(), color.green(), color.blue()])
    }
  }
}

///|
fn read_palette(
  cursor : GifCursor,
  table_size : Int,
) -> Array[Rgba] raise GifError {
  let colors : Array[Rgba] = []
  for _ in 0.. Int {
  1 << ((packed & 0x07) + 1)
}

///|
fn is_bytes(values : Bytes, expected : Array[Byte]) -> Bool {
  if values.length() != expected.length() {
    false
  } else {
    let mut same = true
    for i in 0..