// Copyright 2026 Noverberrain.
// SPDX-License-Identifier: Apache-2.0

///|
/// An unsigned BIT value and its declared width, preserving leading-zero width.
pub struct DecodedBit {
  value : UInt64
  bit_length : Int32
  bytes_read : Int32
} derive(Debug, Eq)

///|
pub extend DecodedBit with Eq::{equal, not_equal}

///|
pub extend DecodedBit with @debug.Debug::{to_repr}

///|
/// Decode a present, non-NULL BIT (16) with declared width 1..64.
/// Metadata contains remainder bits (0..7), then complete bytes (0..8).
/// The value is big-endian; unused high bits of a partial first byte are
/// ignored, matching upstream handling of padding. No shift by 64 is used.
/// `file_offset` is the field's first byte; `column_index` is zero-based.
/// bytes_read is ceil(bit_length/8); trailing input is not consumed.
/// The caller handles row presence/NULL bitmaps. BIT(1) remains an integer.
pub fn TableColumn::decode_bit(
  self : TableColumn,
  data : BytesView,
  file_offset~ : UInt64,
  column_index~ : Int32,
) -> DecodedBit raise DecodeError {
  guard self.wire_type == 16 else {
    raise UnsupportedBitColumn(
      file_offset~,
      column_index~,
      wire_type=self.wire_type,
    )
  }
  guard self.metadata.length() == 2 else {
    raise InvalidBitMetadata(
      file_offset~,
      column_index~,
      reason="expected remainder and byte-count metadata",
    )
  }
  let remainder = self.metadata[0].to_int()
  let whole_bytes = self.metadata[1].to_int()
  let bit_length = whole_bytes * 8 + remainder
  guard remainder <= 7 && bit_length >= 1 && bit_length <= 64 else {
    raise InvalidBitMetadata(
      file_offset~,
      column_index~,
      reason="BIT width must be 1..64 with remainder 0..7",
    )
  }
  let bytes_read = whole_bytes + (if remainder == 0 { 0 } else { 1 })
  guard data.length() >= bytes_read else {
    raise TruncatedColumnValue(
      file_offset~,
      column_index~,
      expected=bytes_read,
      actual=data.length(),
    )
  }
  let mut value = 0UL
  for i in 0..