///|
fn read_direct_chunks(
  bytes : Bytes,
  layout : DataLayout,
  dataspace : Dataspace,
  datatype : Datatype,
  base_address : UInt64,
  filters : Array[Filter],
  output : FixedArray[Byte],
  selection : Array[UInt64]?,
) -> Unit raise Hdf5Error {
  guard layout.element_size == datatype.size else {
    raise InvalidField("chunk element size does not match datatype")
  }
  let rank = dataspace.dimensions.length()
  let chunk_size = chunk_byte_size(layout.chunk_dimensions, datatype.size)
  let start = address_to_offset(layout.data_address, base_address)
  match layout.chunk_index {
    Single(stored_size, mask) => {
      guard dataspace.maximum_dimensions == dataspace.dimensions &&
        dataspace.dimensions ==
        layout.chunk_dimensions.map(size => size.to_uint64()) else {
        raise InvalidField("single chunk dimensions must match dataspace")
      }
      guard stored_size is Some(_) || filters.length() == 0 else {
        raise InvalidField("filtered single chunk is missing its stored size")
      }
      let offsets = Array::make(rank, 0UL)
      if !chunk_contains_selection(
          offsets,
          layout.chunk_dimensions,
          dataspace.dimensions,
          selection,
        ) {
        return
      }
      let decoded = read_filtered_chunk(
        bytes,
        layout.data_address,
        base_address,
        stored_size.unwrap_or(chunk_size.to_uint64()),
        filters,
        mask,
        datatype.size,
        chunk_size,
      )
      copy_chunk(
        decoded,
        decoded.length(),
        offsets,
        layout.chunk_dimensions,
        dataspace.dimensions,
        datatype.size,
        output,
        selection,
      )
    }
    Implicit => {
      guard filters.length() == 0 else {
        raise InvalidField("implicit chunks cannot have filters")
      }
      guard dataspace.maximum_dimensions.length() == rank else {
        raise InvalidField("implicit chunks require maximum dimensions")
      }
      let current_grid : Array[Int64] = []
      let maximum_grid : Array[Int64] = []
      for dimension in 0.. 0 {
          dimension = dimension - 1
          coordinates[dimension] = remaining % current_grid[dimension]
          remaining = remaining / current_grid[dimension]
          offsets[dimension] = (coordinates[dimension] *
          layout.chunk_dimensions[dimension].to_int64()).reinterpret_as_uint64()
        }
        let mut stored_index = 0L
        for dimension in 0..
      raise InvalidField("expected direct chunk index")
  }
}

///|
fn read_source_direct_chunks(
  source : &Hdf5Source,
  layout : DataLayout,
  dataspace : Dataspace,
  datatype : Datatype,
  base_address : UInt64,
  filters : Array[Filter],
  output : FixedArray[Byte],
  selection : Array[UInt64]?,
) -> Unit raise Hdf5Error {
  guard layout.element_size == datatype.size else {
    raise InvalidField("chunk element size does not match datatype")
  }
  let rank = dataspace.dimensions.length()
  let chunk_size = chunk_byte_size(layout.chunk_dimensions, datatype.size)
  let start = source_address_to_offset(layout.data_address, base_address)
  match layout.chunk_index {
    Single(stored_size, mask) => {
      guard dataspace.maximum_dimensions == dataspace.dimensions &&
        dataspace.dimensions ==
        layout.chunk_dimensions.map(size => size.to_uint64()) else {
        raise InvalidField("single chunk dimensions must match dataspace")
      }
      guard stored_size is Some(_) || filters.length() == 0 else {
        raise InvalidField("filtered single chunk is missing its stored size")
      }
      let offsets = Array::make(rank, 0UL)
      if !chunk_contains_selection(
          offsets,
          layout.chunk_dimensions,
          dataspace.dimensions,
          selection,
        ) {
        return
      }
      let decoded = read_source_filtered_chunk(
        source,
        layout.data_address,
        base_address,
        stored_size.unwrap_or(chunk_size.to_uint64()),
        filters,
        mask,
        datatype.size,
        chunk_size,
      )
      copy_chunk(
        decoded,
        decoded.length(),
        offsets,
        layout.chunk_dimensions,
        dataspace.dimensions,
        datatype.size,
        output,
        selection,
      )
    }
    Implicit => {
      guard filters.length() == 0 else {
        raise InvalidField("implicit chunks cannot have filters")
      }
      guard dataspace.maximum_dimensions.length() == rank else {
        raise InvalidField("implicit chunks require maximum dimensions")
      }
      let current_grid : Array[Int64] = []
      let maximum_grid : Array[Int64] = []
      for dimension in 0.. 0 {
          dimension = dimension - 1
          coordinates[dimension] = remaining % current_grid[dimension]
          remaining = remaining / current_grid[dimension]
          offsets[dimension] = (coordinates[dimension] *
          layout.chunk_dimensions[dimension].to_int64()).reinterpret_as_uint64()
        }
        let mut stored_index = 0L
        for dimension in 0..
      raise InvalidField("expected direct chunk index")
  }
}