///|
/// A monotonically increasing metric backed by deterministic portable storage.
pub struct Counter {
  descriptor : Descriptor
  value : @storage.ScalarCell
}

///|
pub fn Counter::new(
  name : String,
  help? : String = "",
  unit? : String,
  const_labels? : Array[Label] = [],
) -> Counter raise MetricError {
  let descriptor = make_metric_descriptor(
    name,
    CounterKind,
    help,
    unit,
    const_labels,
  )
  { descriptor, value: @storage.ScalarCell::new(0.0) }
}

///|
pub fn Counter::name(self : Counter) -> String {
  self.descriptor.name()
}

///|
pub fn Counter::help(self : Counter) -> String {
  self.descriptor.help()
}

///|
pub fn Counter::unit(self : Counter) -> String? {
  self.descriptor.unit()
}

///|
pub fn Counter::labels(self : Counter) -> Array[Label] {
  self.descriptor.const_labels()
}

///|
pub fn Counter::descriptor(self : Counter) -> Descriptor {
  self.descriptor
}

///|
pub fn Counter::inc(self : Counter) -> Unit {
  self.value.add(1.0)
}

///|
pub fn Counter::add(self : Counter, delta : Double) -> Unit raise MetricError {
  if delta.is_nan() || delta.is_inf() {
    raise NonFiniteCounterDelta(delta)
  }
  if delta < 0.0 {
    raise NegativeCounterDelta(delta)
  }
  self.value.add(delta)
}

///|
pub fn Counter::get(self : Counter) -> Double {
  self.value.get()
}

///|
pub fn Counter::snapshot(self : Counter) -> ScalarMetricSnapshot {
  { value: self.value.get() }
}