///|
fn is_ascii_letter(char : Char) -> Bool {
  match char {
    'a'..='z' | 'A'..='Z' => true
    _ => false
  }
}

///|
fn is_ascii_digit(char : Char) -> Bool {
  match char {
    '0'..='9' => true
    _ => false
  }
}

///|
fn is_valid_identifier(value : String, allow_colon : Bool) -> Bool {
  if value.is_empty() {
    return false
  }
  let mut index = 0
  for char in value {
    let valid = if index == 0 {
      is_ascii_letter(char) || char == '_' || (allow_colon && char == ':')
    } else {
      is_ascii_letter(char) ||
      is_ascii_digit(char) ||
      char == '_' ||
      (allow_colon && char == ':')
    }
    if !valid {
      return false
    }
    index += 1
  }
  true
}

///|
fn is_valid_metric_name(name : String) -> Bool {
  is_valid_identifier(name, true)
}

///|
pub fn validate_label_name(name : String) -> Unit raise MetricError {
  if !is_valid_identifier(name, false) {
    raise InvalidLabelName(name)
  }
  if name.has_prefix("__") {
    raise ReservedLabelName(name)
  }
}

///|
fn canonical_const_labels(
  labels : Array[Label],
) -> Array[Label] raise MetricError {
  for index, label in labels {
    validate_label_name(label.name)
    for previous in 0.. left.name.compare(right.name))
  canonical
}

///|
fn validate_variable_label_names(
  names : Array[String],
) -> Unit raise MetricError {
  for index, name in names {
    validate_label_name(name)
    for previous in 0..