use std::collections::{HashMap, BTreeSet};
use std::hash::Hasher;
use fnv::FnvHasher;
use proto::LabelPair;
use errors::{Result, Error};
use metrics::SEPARATOR_BYTE;
#[derive(Clone, Debug)]
pub struct Desc {
pub fq_name: String,
pub help: String,
pub const_label_pairs: Vec<LabelPair>,
pub variable_labels: Vec<String>,
pub id: u64,
pub dim_hash: u64,
}
impl Desc {
pub fn new(fq_name: String,
help: String,
variable_labels: Vec<String>,
const_labels: HashMap<String, String>)
-> Result<Desc> {
let mut desc = Desc {
fq_name: fq_name.clone(),
help: help,
const_label_pairs: Vec::with_capacity(const_labels.len()),
variable_labels: variable_labels,
id: 0,
dim_hash: 0,
};
if desc.help.is_empty() {
return Err(Error::Msg("empty help string".into()));
}
let mut label_values = Vec::with_capacity(const_labels.len() + 1);
label_values.push(fq_name);
let mut label_names = BTreeSet::new();
for label_name in const_labels.keys() {
if !label_names.insert(label_name.clone()) {
return Err(Error::Msg(format!("duplicate const label name {}", label_name)));
}
}
for label_name in &label_names {
label_values.push(const_labels.get(label_name).cloned().unwrap());
}
for label_name in &desc.variable_labels {
if !label_names.insert(format!("${}", label_name)) {
return Err(Error::Msg(format!("duplicate variable label name {}", label_name)));
}
}
let mut vh = FnvHasher::default();
for val in &label_values {
vh.write(val.as_bytes());
vh.write_u8(SEPARATOR_BYTE);
}
desc.id = vh.finish();
let mut lh = FnvHasher::default();
lh.write(desc.help.as_bytes());
lh.write_u8(SEPARATOR_BYTE);
for label_name in &label_names {
lh.write(label_name.as_bytes());
lh.write_u8(SEPARATOR_BYTE);
}
desc.dim_hash = lh.finish();
for (key, value) in const_labels {
let mut label_pair = LabelPair::new();
label_pair.set_name(key);
label_pair.set_value(value);
desc.const_label_pairs.push(label_pair);
}
desc.const_label_pairs.sort();
Ok(desc)
}
}