use std::hash::Hasher as _;
use hash32::{FnvHasher, Hasher as _};
#[doc(inline)]
pub use relay_base_schema::metrics::{
CustomUnit, DurationUnit, FractionUnit, InformationUnit, MetricName, MetricNamespace,
MetricResourceIdentifier, MetricType, MetricUnit, ParseMetricError, ParseMetricUnitError,
};
#[doc(inline)]
pub use relay_common::time::UnixTimestamp;
#[doc(inline)]
pub use unescaper::Error as UnescapeError;
use crate::FiniteF64;
pub type CounterType = FiniteF64;
pub type DistributionType = FiniteF64;
pub type SetType = u32;
pub type GaugeType = FiniteF64;
pub(crate) fn is_valid_tag_key(tag_key: &str) -> bool {
for &byte in tag_key.as_bytes() {
if (byte as char).is_ascii_control() {
return false;
}
}
true
}
#[allow(unused)]
pub(crate) fn escape_tag_value(raw: &str) -> String {
let mut escaped = String::with_capacity(raw.len());
for c in raw.chars() {
match c {
'\t' => escaped.push_str("\\t"),
'\n' => escaped.push_str("\\n"),
'\r' => escaped.push_str("\\r"),
'\\' => escaped.push_str("\\\\"),
'|' => escaped.push_str("\\u{7c}"),
',' => escaped.push_str("\\u{2c}"),
_ if c.is_control() => (),
_ => escaped.push(c),
}
}
escaped
}
pub(crate) fn unescape_tag_value(escaped: &str) -> Result<String, UnescapeError> {
let mut unescaped = unescaper::unescape(escaped)?;
validate_tag_value(&mut unescaped);
Ok(unescaped)
}
pub(crate) fn validate_tag_value(tag_value: &mut String) {
tag_value.retain(|c| !c.is_control());
}
pub(crate) fn hash_set_value(string: &str) -> u32 {
let mut hasher = FnvHasher::default();
hasher.write(string.as_bytes());
hasher.finish32()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_unescape_tag_value() {
assert_eq!(unescape_tag_value("plain").unwrap(), "plain");
assert_eq!(unescape_tag_value("plain text").unwrap(), "plain text");
assert_eq!(unescape_tag_value("plain%text").unwrap(), "plain%text");
assert_eq!(
unescape_tag_value("plain \\\\ text").unwrap(),
"plain \\ text"
);
assert_eq!(
unescape_tag_value("plain\\u{2c}text").unwrap(),
"plain,text"
);
assert_eq!(
unescape_tag_value("plain\\u{7c}text").unwrap(),
"plain|text"
);
assert_eq!(unescape_tag_value("plain 😅").unwrap(), "plain 😅");
assert_eq!(
unescape_tag_value("plain \\u{5c} text").unwrap(),
"plain \\ text"
);
assert_eq!(unescape_tag_value("plain\\ntext").unwrap(), "plaintext");
assert_eq!(unescape_tag_value("plain\\rtext").unwrap(), "plaintext");
assert_eq!(unescape_tag_value("plain\\ttext").unwrap(), "plaintext");
assert_eq!(unescape_tag_value("plain\u{7}text").unwrap(), "plaintext");
}
#[test]
fn test_escape_tag_value() {
assert_eq!(escape_tag_value("plain"), "plain");
assert_eq!(escape_tag_value("plain text"), "plain text");
assert_eq!(escape_tag_value("plain%text"), "plain%text");
assert_eq!(escape_tag_value("plain \\ text"), "plain \\\\ text");
assert_eq!(escape_tag_value("plain,text"), "plain\\u{2c}text");
assert_eq!(escape_tag_value("plain|text"), "plain\\u{7c}text");
assert_eq!(escape_tag_value("plain 😅"), "plain 😅");
assert_eq!(escape_tag_value("plain\ntext"), "plain\\ntext");
assert_eq!(escape_tag_value("plain\rtext"), "plain\\rtext");
assert_eq!(escape_tag_value("plain\ttext"), "plain\\ttext");
assert_eq!(escape_tag_value("plain\u{07}text"), "plaintext");
assert_eq!(escape_tag_value("plain\u{9c}text"), "plaintext");
}
}