// bitreader.mbt
//
// MSB-first 位读取器:FLAC 的比特流最高位先读——每个字节内 bit7 最先读出,
// 跨字节时高位字节先读。这与 moonvorbis 里 Vorbis 的 LSB-first 恰好相反。
//
// 越界读取不 panic:读到末尾会置 `truncated` 标志并返回 0,
// 由调用方在帧边界上用 `check` 统一转成错误。

///|
/// MSB-first 位读取器。
struct BitReader {
  data : Bytes
  mut pos : Int32 // 当前位位置,从 0 开始
  mut truncated : Bool // 是否发生过越界读取
}

///|
/// 用整段字节序列构造从第 0 位开始的读取器。
fn BitReader::new(data : Bytes) -> BitReader {
  { data, pos: 0, truncated: false, }
}

///|
/// 总位数。
pub fn BitReader::total_bits(self : BitReader) -> Int32 {
  self.data.length() * 8
}

///|
/// 剩余可读位数。
pub fn BitReader::remaining_bits(self : BitReader) -> Int32 {
  self.total_bits() - self.pos
}

///|
/// 移动到位位置 `pos`(字节对齐处)。越界位置视为读取失败而不是 panic。
fn BitReader::seek(self : BitReader, pos : Int32) -> Unit {
  if pos < 0 || pos > self.total_bits() {
    self.truncated = true
    self.pos = if pos < 0 { 0 } else { self.total_bits() }
    return
  }
  self.pos = pos
}

///|
/// 读 1 位(MSB-first)。越界时返回 0 并置 truncated。
pub fn BitReader::read_bit(self : BitReader) -> Int32 {
  let byte_index = self.pos >> 3
  if byte_index >= self.data.length() {
    self.truncated = true
    return 0
  }
  let shift = 7 - (self.pos & 7)
  self.pos += 1
  (self.data.unsafe_get(byte_index).to_int() >> shift) & 1
}

///|
/// 连续读 `n` 位(`0 <= n <= 40`),按位扩展后的 Int64 返回。
/// 用 Int64 累加避免 31 位以上左移溢出 Int。
fn BitReader::read_bits64(self : BitReader, n : Int32) -> Int64 {
  guard! n >= 0 && n <= 40
  let mut acc = 0L
  for _ in 0.. Int64 {
  if n <= 0 {
    if n < 0 {
      self.truncated = true
    }
    return 0L
  }
  if n >= 64 {
    self.truncated = true
    return 0L
  }
  let v = self.read_bits64(n)
  let limit = Int64::from_int(1) << (n - 1)
  if v >= limit {
    v - (Int64::from_int(1) << n)
  } else {
    v
  }
}

///|
/// 是否落在字节边界上。
fn BitReader::is_aligned(self : BitReader) -> Bool {
  (self.pos & 7) == 0
}

///|
/// 若发生过越界读取,抛出 Truncated 错误(带发生时的位置)。
fn BitReader::check(self : BitReader) -> Unit raise FlacError {
  if self.truncated {
    let offset = self.pos
    self.truncated = false
    raise Truncated(offset~, need=1, actual=self.data.length() * 8)
  }
}