use lazy_static::lazy_static;
use std::cell::RefCell;
use std::path::{Path, PathBuf};
use std::sync::Arc;
#[cfg(feature = "redactions")]
use crate::{
content::Content,
redaction::{dynamic_redaction, ContentPath, Redaction, Selector},
};
lazy_static! {
static ref DEFAULT_SETTINGS: Arc<ActualSettings> = Arc::new(ActualSettings {
sort_maps: false,
snapshot_path: "snapshots".into(),
#[cfg(feature = "redactions")]
redactions: Redactions::default(),
});
}
thread_local!(static CURRENT_SETTINGS: RefCell<Settings> = RefCell::new(Settings::new()));
#[cfg(feature = "redactions")]
#[derive(Clone, Default)]
pub struct Redactions(Vec<(Selector<'static>, Arc<Redaction>)>);
#[cfg(feature = "redactions")]
impl<'a> From<Vec<(&'a str, Redaction)>> for Redactions {
fn from(value: Vec<(&'a str, Redaction)>) -> Redactions {
Redactions(
value
.into_iter()
.map(|x| (Selector::parse(x.0).unwrap().make_static(), Arc::new(x.1)))
.collect(),
)
}
}
#[derive(Clone)]
#[doc(hidden)]
pub struct ActualSettings {
pub sort_maps: bool,
pub snapshot_path: PathBuf,
#[cfg(feature = "redactions")]
pub redactions: Redactions,
}
#[derive(Clone)]
pub struct Settings {
inner: Arc<ActualSettings>,
}
impl Default for Settings {
fn default() -> Settings {
Settings {
inner: DEFAULT_SETTINGS.clone(),
}
}
}
impl Settings {
pub fn new() -> Settings {
Settings::default()
}
#[doc(hidden)]
pub fn _private_inner_mut(&mut self) -> &mut ActualSettings {
Arc::make_mut(&mut self.inner)
}
pub fn set_sort_maps(&mut self, value: bool) {
self._private_inner_mut().sort_maps = value;
}
pub fn sort_maps(&self) -> bool {
self.inner.sort_maps
}
#[cfg(feature = "redactions")]
pub fn add_redaction<R: Into<Redaction>>(&mut self, selector: &str, replacement: R) {
self._private_inner_mut().redactions.0.push((
Selector::parse(selector).unwrap().make_static(),
Arc::new(replacement.into()),
));
}
#[cfg(feature = "redactions")]
pub fn add_dynamic_redaction<I, F>(&mut self, selector: &str, func: F)
where
I: Into<Content>,
F: Fn(Content, ContentPath<'_>) -> I + Send + Sync + 'static,
{
self.add_redaction(selector, dynamic_redaction(func));
}
#[cfg(feature = "redactions")]
pub fn set_redactions<R: Into<Redactions>>(&mut self, redactions: R) {
self._private_inner_mut().redactions = redactions.into();
}
#[cfg(feature = "redactions")]
pub fn clear_redactions(&mut self) {
self._private_inner_mut().redactions.0.clear();
}
#[cfg(feature = "redactions")]
pub(crate) fn iter_redactions(&self) -> impl Iterator<Item = (&Selector, &Redaction)> {
self.inner
.redactions
.0
.iter()
.map(|&(ref a, ref b)| (a, &**b))
}
pub fn set_snapshot_path<P: AsRef<Path>>(&mut self, path: P) {
self._private_inner_mut().snapshot_path = path.as_ref().to_path_buf();
}
pub fn snapshot_path(&self) -> &Path {
&self.inner.snapshot_path
}
pub fn bind<F: FnOnce()>(&self, f: F) {
CURRENT_SETTINGS.with(|x| {
let old = {
let mut current = x.borrow_mut();
let old = current.inner.clone();
current.inner = self.inner.clone();
old
};
f();
let mut current = x.borrow_mut();
current.inner = old;
})
}
pub fn bind_to_thread(&self) {
CURRENT_SETTINGS.with(|x| {
x.borrow_mut().inner = self.inner.clone();
})
}
pub(crate) fn with<R, F: FnOnce(&Settings) -> R>(f: F) -> R {
CURRENT_SETTINGS.with(|x| f(&*x.borrow()))
}
}