use std::{env, error, fmt, sync};
use super::{NodeSpec, Scru64Generator, Scru64Id};
#[doc = concat!("\n\n", include_str!("doc_global_gen.md"), "\n\n")]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GlobalGenerator;
static G: sync::OnceLock<sync::Mutex<Scru64Generator>> = sync::OnceLock::new();
impl GlobalGenerator {
fn lock(&self) -> sync::MutexGuard<'static, Scru64Generator> {
G.get_or_init(|| {
use error::Error as _;
let node_spec = read_env_var("SCRU64_NODE_SPEC")
.unwrap_or_else(|err| panic!("scru64: {}: {}", err, err.source().unwrap()));
sync::Mutex::new(Scru64Generator::new(node_spec))
})
.lock()
.expect("scru64: could not lock global generator")
}
pub fn initialize(&self, node_spec: NodeSpec) -> Result<(), NodeSpec> {
let mut wrap = Some(node_spec);
G.get_or_init(|| sync::Mutex::new(Scru64Generator::new(wrap.take().unwrap())));
match wrap {
None => Ok(()),
Some(node_spec) => Err(node_spec),
}
}
pub fn generate(&self) -> Option<Scru64Id> {
self.lock().generate()
}
pub fn node_id(&self) -> u32 {
self.lock().node_id()
}
pub fn node_id_size(&self) -> u8 {
self.lock().node_id_size()
}
pub fn node_spec(&self) -> NodeSpec {
self.lock().node_spec()
}
}
fn read_env_var(key: &str) -> Result<NodeSpec, EnvVarError> {
env::var(key)
.map_err(|err| EnvVarError {
key,
source: Box::new(err),
})?
.parse()
.map_err(|err| EnvVarError {
key,
source: Box::new(err),
})
}
#[derive(Debug)]
struct EnvVarError<'a> {
key: &'a str,
source: Box<dyn error::Error>,
}
impl<'a> fmt::Display for EnvVarError<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "could not read config from {} env var", self.key)
}
}
impl<'a> error::Error for EnvVarError<'a> {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(self.source.as_ref())
}
}