///| The unpaged fixed array covers modern fixed-extent chunked datasets.

///|
/// Paged arrays and extensible arrays remain explicit unsupported profiles.
fn H5File::fixed_array_chunks(
  self : H5File,
  info : DatasetInfo,
) -> Array[ChunkInfo] raise H5Error {
  guard info.storage is FixedArray(header, dims, layout_page_bits) else {
    raise Invalid("not fixed-array storage", 0)
  }
  guard info.dataspace is Simple(shape) else {
    raise Invalid("fixed-array scalar/null", 0)
  }
  guard header is Some(header) else { return [] }
  let h = cursor(self.data, header, self.sb.eof - header)
  h.signature(b"FAHD")
  if h.u8() != 0 {
    raise Unsupported("fixed-array version", header)
  }
  let client = h.u8()
  let entry_size = h.u8()
  let page_bits = h.u8()
  if client > 1 || page_bits != layout_page_bits || page_bits > 30 {
    raise Unsupported("fixed-array client/page configuration", header)
  }
  let count = h.index(self.sb.size_width)
  let data_address = h.address(self.sb.offset_width, self.sb.base)
  h.skip(4)
  verify_checksum(self.data, header, h.pos - header)
  if count > self.limits.max_objects {
    raise Limit("fixed-array entries")
  }
  if count > 1 << page_bits {
    raise Unsupported("paged fixed-array index", header)
  }
  let grid : Array[Int32] = []
  let mut total = 1
  let mut raw_size = info.datatype.width()
  for i = 0; i < shape.length(); i = i + 1 {
    let n = shape[i] / dims[i] + (if shape[i] % dims[i] != 0 { 1 } else { 0 })
    grid.push(n)
    total = checked_mul(total, n)
    raw_size = checked_mul(raw_size, dims[i])
  }
  if count != total {
    raise Unsupported(
      "fixed-array maximum extent differs from current grid", header,
    )
  }
  let size_width = if client == 0 {
    0
  } else {
    entry_size - self.sb.offset_width - 4
  }
  if (client == 0 && entry_size != self.sb.offset_width) ||
    (client == 1 && (size_width < 1 || size_width > 8)) {
    raise Invalid("fixed-array entry size", header)
  }
  guard data_address is Some(address) else { return [] }
  let bytes = checked_add(
    checked_add(10, self.sb.offset_width),
    checked_mul(count, entry_size),
  )
  if bytes > self.limits.max_metadata_bytes {
    raise Limit("fixed-array metadata bytes")
  }
  self.check_range(address, bytes)
  verify_checksum(self.data, address, bytes)
  let c = cursor(self.data, address, bytes - 4)
  c.signature(b"FADB")
  if c.u8() != 0 || c.u8() != client {
    raise Invalid("fixed-array data block client/version", address)
  }
  if c.address(self.sb.offset_width, self.sb.base) != Some(header) {
    raise Invalid("fixed-array header backlink", address)
  }
  let out : Array[ChunkInfo] = []
  for index = 0; index < count; index = index + 1 {
    let chunk_address = c.address(self.sb.offset_width, self.sb.base)
    let stored = if client == 0 { raw_size } else { c.index(size_width) }
    let mask = if client == 0 { 0U } else { c.uint(4).to_uint() }
    guard chunk_address is Some(chunk_address) else { continue }
    if stored <= 0 || stored > self.limits.max_file_bytes {
      raise Limit("fixed-array stored chunk bytes")
    }
    self.check_range(chunk_address, stored)
    let origin = Array::make(shape.length(), 0)
    let mut left = index
    for j = shape.length() - 1; j >= 0; j = j - 1 {
      origin[j] = checked_mul(left % grid[j], dims[j])
      left /= grid[j]
    }
    out.push({
      origin,
      address: chunk_address,
      stored_bytes: stored,
      filter_mask: mask,
    })
  }
  out
}