use once_cell::sync::Lazy;
use std::sync::Mutex;
use crate::field::clear_codec_cache;
static GLOBAL_CONFIG: Lazy<Mutex<Option<Config>>> = Lazy::new(|| Mutex::new(None));
thread_local! {
static THREAD_LOCAL_CONFIG: std::cell::RefCell<Option<Config>> =
const { std::cell::RefCell::new(None) };
}
#[derive(Clone)]
pub struct Config {
pub(crate) hmac_length: u8,
pub(crate) key: Vec<u8>,
pub(crate) zero_pad_length: u8,
}
#[derive(Debug)]
pub enum ConfigError {
InvalidMacLength,
InvalidVersion,
InvalidZeroPadLength,
}
impl Config {
pub fn new(key: &[u8]) -> Self {
Config {
hmac_length: 4,
key: key.to_vec(),
zero_pad_length: 4,
}
}
pub fn hmac_length(mut self, hmac_length: u8) -> Result<Self, ConfigError> {
if hmac_length > 8 {
Err(ConfigError::InvalidMacLength)
} else {
self.hmac_length = hmac_length;
Ok(self)
}
}
pub fn zero_pad_length(mut self, zero_pad_length: u8) -> Result<Self, ConfigError> {
if zero_pad_length > 8 {
Err(ConfigError::InvalidZeroPadLength)
} else {
self.zero_pad_length = zero_pad_length;
Ok(self)
}
}
pub fn set_global(config: Config) {
let mut global_config = GLOBAL_CONFIG.lock().unwrap();
*global_config = Some(config);
}
pub fn set_thread_local(config: Config) {
THREAD_LOCAL_CONFIG.with(|tl_config| {
*tl_config.borrow_mut() = Some(config);
});
clear_codec_cache();
}
pub fn clear_thread_local() {
THREAD_LOCAL_CONFIG.with(|tl_config| {
*tl_config.borrow_mut() = None;
});
clear_codec_cache();
}
pub fn effective() -> Option<Config> {
let thread_local = THREAD_LOCAL_CONFIG.with(|tl_config| tl_config.borrow().clone());
if thread_local.is_some() {
thread_local
} else {
GLOBAL_CONFIG.lock().unwrap().clone()
}
}
pub fn global() -> Option<Config> {
GLOBAL_CONFIG.lock().unwrap().clone()
}
}