use std::sync::{Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use erased_serde::Deserializer as DynamicDeserializer;
pub use default::DefaultSource;
use null_deserializer::NullDeserializer;
pub static CONFIGURATION: ActiveConfiguration = ActiveConfiguration {
init: ONCE_INIT,
is_overriden: ATOMIC_BOOL_INIT,
};
static mut SOURCE: Option<&'static (Fn(&'static str) -> Box<DynamicDeserializer> + Send + Sync + 'static)> = None;
pub trait ConfigSource: Send + Sync + 'static {
fn init() -> Self;
fn prepare(&self, package: &'static str) -> Box<DynamicDeserializer<'static>>;
}
pub struct ActiveConfiguration {
init: Once,
is_overriden: AtomicBool,
}
impl ActiveConfiguration {
pub fn set<T: ConfigSource>(&'static self, source: T) {
self.init.call_once(|| {
self.is_overriden.store(true, Ordering::Relaxed);
let init = Box::new(move |s| source.prepare(s));
unsafe { SOURCE = Some(&*Box::into_raw(init)) }
});
}
pub fn get(&'static self, package: &'static str) -> Box<DynamicDeserializer> {
self.init.call_once(|| {
fn null_deserializer(_package: &'static str) -> Box<DynamicDeserializer> {
Box::new(DynamicDeserializer::erase(NullDeserializer))
}
unsafe { SOURCE = Some(&null_deserializer) }
});
unsafe { SOURCE.unwrap()(package) }
}
pub fn is_default(&'static self) -> bool {
!self.is_overriden()
}
pub fn is_overriden(&'static self) -> bool {
self.is_overriden.load(Ordering::Relaxed)
}
}