///|
#derive(Debug, Eq)
pub struct ArchiveInfo {
  resolution : Int64
  capacity : Int32
  retained : Int32
  oldest : Int64?
  newest : Int64?
  pending_known : Int32
}

///|
/// Coverage metadata distinguishes expired history from retained unknown values.
pub fn Store::info(
  self : Store,
  archive_index : Int32,
) -> ArchiveInfo raise ArchiveError {
  if archive_index < 0 || archive_index >= self.archives.length() {
    raise InvalidConfig("invalid archive index")
  }
  let a = self.archives[archive_index]
  let n = a.data.length()
  {
    resolution: a.spec.factor.to_int64() * self.step.to_int64(),
    capacity: a.spec.rows,
    retained: n,
    oldest: if n == 0 {
      None
    } else {
      Some(a.data[a.head].timestamp)
    },
    newest: if n == 0 {
      None
    } else {
      Some(a.data[(a.head + n - 1) % n].timestamp)
    },
    pending_known: a.count,
  }
}

///| Explicit 32-bit counter conversion. A decrease is unknown unless wrap is enabled.

///|
/// The caller must distinguish a reset from a wrap; this function cannot infer it.
pub fn counter32_rate(
  previous : UInt32,
  current : UInt32,
  elapsed_seconds : Int32,
  wrap~ : Bool = false,
) -> Double? raise ArchiveError {
  if elapsed_seconds <= 0 {
    raise InvalidSample("elapsed seconds must be positive")
  }
  if current >= previous {
    Some(
      (current.to_int64() - previous.to_int64()).to_double() /
      elapsed_seconds.to_double(),
    )
  } else if wrap {
    Some(
      (4294967296L - previous.to_int64() + current.to_int64()).to_double() /
      elapsed_seconds.to_double(),
    )
  } else {
    None
  }
}