///|
/// Return whether a string is a legacy OpenMetrics metric identifier.
///
/// This intentionally accepts the interoperable ASCII form used by the
/// Prometheus/OpenMetrics text grammar:
/// `[A-Za-z_:][A-Za-z0-9_:]*`.
pub fn is_valid_metric_name(name : StringView) -> Bool {
if name.is_empty() {
return false
}
let mut first = true
for char in name.iter() {
if first {
if !(char.is_ascii_alphabetic() || char == '_' || char == ':') {
return false
}
first = false
} else if !(char.is_ascii_alphabetic() ||
char.is_ascii_digit() ||
char == '_' ||
char == ':') {
return false
}
}
true
}
///|
/// Return whether a string is a legacy OpenMetrics label identifier.
pub fn is_valid_label_name(name : StringView) -> Bool {
if name.is_empty() {
return false
}
let mut first = true
for char in name.iter() {
if first {
if !(char.is_ascii_alphabetic() || char == '_') {
return false
}
first = false
} else if !(char.is_ascii_alphabetic() ||
char.is_ascii_digit() ||
char == '_') {
return false
}
}
true
}
///|
/// Escape a label value for a quoted OpenMetrics label string.
pub fn escape_label_value(value : StringView) -> String {
let out = StringBuilder(size_hint=value.length())
for char in value.iter() {
match char {
'\\' => out.write_string("\\\\")
'"' => out.write_string("\\\"")
'\n' => out.write_string("\\n")
_ => out.write_char(char)
}
}
out.to_string()
}
///|
/// Escape HELP text using the quoted-string escapes from OpenMetrics.
pub fn escape_help(value : StringView) -> String {
let out = StringBuilder(size_hint=value.length())
for char in value.iter() {
match char {
'\\' => out.write_string("\\\\")
'"' => out.write_string("\\\"")
'\n' => out.write_string("\\n")
_ => out.write_char(char)
}
}
out.to_string()
}
///|
fn unescape_text(
value : StringView,
allow_quote : Bool,
) -> Result[String, String] {
let chars = value.to_array()
let out = StringBuilder(size_hint=value.length())
let mut i = 0
while i < chars.length() {
let char = chars[i]
if char != '\\' {
if char == '"' {
return Err("unescaped quote in escaped text")
}
out.write_char(char)
i += 1
continue
}
if i + 1 >= chars.length() {
return Err("trailing backslash in escaped text")
}
let escaped = chars[i + 1]
match escaped {
'\\' => out.write_char('\\')
'n' => out.write_char('\n')
'"' =>
if allow_quote {
out.write_char('"')
} else {
return Err("quote escape is not valid in HELP text")
}
_ => return Err("unsupported escape sequence \\\{escaped}")
}
i += 2
}
Ok(out.to_string())
}
///|
/// Decode the contents of a quoted label value.
pub fn unescape_label_value(value : StringView) -> Result[String, String] {
unescape_text(value, true)
}
///|
/// Decode escaped HELP text.
pub fn unescape_help(value : StringView) -> Result[String, String] {
unescape_text(value, true)
}