use atomic_immut::AtomicImmut;
use std;
use std::fmt;
use std::ops::Deref;
use {ErrorKind, Result};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Label {
name: String,
value: String,
}
impl Label {
pub fn new(name: &str, value: &str) -> Result<Self> {
track!(
Self::validate_name(name),
"name={:?}, value={:?}",
name,
value
)?;
Ok(Label {
name: name.to_string(),
value: value.to_string(),
})
}
pub fn name(&self) -> &str {
&self.name
}
pub fn value(&self) -> &str {
&self.value
}
fn validate_name(name: &str) -> Result<()> {
track_assert!(!name.is_empty(), ErrorKind::InvalidInput);
track_assert!(!name.starts_with("__"), ErrorKind::InvalidInput, "Reserved");
match name.as_bytes()[0] as char {
'a'..='z' | 'A'..='Z' | '_' => {}
_ => track_panic!(ErrorKind::InvalidInput),
}
for c in name.chars().skip(1) {
match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {}
_ => track_panic!(ErrorKind::InvalidInput),
}
}
Ok(())
}
}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}=\"", self.name)?;
for c in self.value.chars() {
match c {
'\\' => write!(f, "\\\\")?,
'\n' => write!(f, "\\\\n")?,
'"' => write!(f, "\\\"")?,
_ => write!(f, "{}", c)?,
}
}
write!(f, "\"")
}
}
#[derive(Debug)]
pub struct Labels(AtomicImmut<Vec<Label>>);
impl Labels {
pub fn len(&self) -> usize {
self.0.load().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, name: &str) -> Option<&Label> {
self.iter().find(|l| l.name() == name)
}
pub fn iter(&self) -> Iter {
let labels = self.0.load();
let inner = unsafe { std::mem::transmute(labels.iter()) };
Iter { labels, inner }
}
pub(crate) fn new(labels: Vec<Label>) -> Self {
Labels(AtomicImmut::new(labels))
}
}
impl fmt::Display for Labels {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{")?;
for (i, label) in self.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{}", label)?;
}
write!(f, "}}")?;
Ok(())
}
}
#[derive(Debug)]
pub struct LabelsMut<'a> {
inner: &'a Labels,
reserved: Option<&'static str>,
}
impl<'a> LabelsMut<'a> {
pub fn insert(&mut self, name: &str, value: &str) -> Result<()> {
track_assert_ne!(
self.reserved.map(|s| &*s),
Some(name),
ErrorKind::InvalidInput
);
let label = track!(Label::new(name, value))?;
self.inner.0.update(move |labels| {
let mut labels = labels.clone();
labels.retain(|l| l.name != label.name);
labels.push(label.clone());
labels.sort();
labels
});
Ok(())
}
pub fn remove(&mut self, name: &str) {
self.inner
.0
.update(|labels| labels.iter().filter(|l| l.name != name).cloned().collect());
}
pub fn clear(&mut self) {
self.inner.0.store(Vec::new());
}
pub(crate) fn new(labels: &'a Labels, reserved: Option<&'static str>) -> Self {
LabelsMut {
inner: labels,
reserved,
}
}
}
impl<'a> Deref for LabelsMut<'a> {
type Target = Labels;
fn deref(&self) -> &Self::Target {
self.inner
}
}
#[derive(Debug)]
pub struct Iter<'a> {
labels: std::sync::Arc<Vec<Label>>,
inner: std::slice::Iter<'a, Label>,
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Label;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}