#![doc(html_root_url="https://sfackler.github.io/rust-log-mdc/doc/v0.1.0")]
#![warn(missing_docs)]
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::hash::Hash;
thread_local!(static MDC: RefCell<HashMap<String, String>> = RefCell::new(HashMap::new()));
pub fn insert<K, V>(key: K, value: V) -> Option<String>
where K: Into<String>,
V: Into<String>
{
MDC.with(|m| m.borrow_mut().insert(key.into(), value.into()))
}
pub fn insert_scoped<K, V>(key: K, value: V) -> InsertGuard
where K: Into<String>,
V: Into<String>
{
let key = key.into();
let old_value = insert(&*key, value);
InsertGuard {
key: Some(key),
old_value: old_value,
}
}
pub fn extend<K, V, I>(entries: I)
where K: Into<String>,
V: Into<String>,
I: IntoIterator<Item = (K, V)>
{
MDC.with(|m| m.borrow_mut().extend(entries.into_iter().map(|(k, v)| (k.into(), v.into()))));
}
pub fn extend_scoped<K, V, I>(entries: I) -> ExtendGuard
where K: Into<String>,
V: Into<String>,
I: IntoIterator<Item = (K, V)>
{
MDC.with(|m| {
let mut m = m.borrow_mut();
let old_entries = entries.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.map(|(k, v)| {
let v = m.insert(k.clone(), v);
(k, v)
})
.collect();
ExtendGuard(old_entries)
})
}
pub fn get<Q: ?Sized, F, T>(key: &Q, f: F) -> T
where String: Borrow<Q>,
Q: Hash + Eq,
F: FnOnce(Option<&str>) -> T
{
MDC.with(|m| f(m.borrow().get(key).map(|v| &**v)))
}
pub fn remove<Q: ?Sized>(key: &Q) -> Option<String>
where String: Borrow<Q>,
Q: Hash + Eq
{
MDC.with(|m| m.borrow_mut().remove(key))
}
pub fn clear() {
MDC.with(|m| m.borrow_mut().clear())
}
pub fn iter<F>(mut f: F)
where F: FnMut(&str, &str)
{
MDC.with(|m| {
for (key, value) in m.borrow().iter() {
f(key, value)
}
})
}
pub struct InsertGuard {
key: Option<String>,
old_value: Option<String>,
}
impl Drop for InsertGuard {
fn drop(&mut self) {
let key = self.key.take().unwrap();
match self.old_value.take() {
Some(value) => insert(key, value),
None => remove(&key),
};
}
}
pub struct ExtendGuard(Vec<(String, Option<String>)>);
impl Drop for ExtendGuard {
fn drop(&mut self) {
MDC.with(|m| {
let mut m = m.borrow_mut();
for (key, value) in self.0.drain(..) {
match value {
Some(value) => m.insert(key, value),
None => m.remove(&key),
};
}
})
}
}