use serde::de::DeserializeOwned;
use super::Builder;
#[cfg(feature = "watch")]
#[cfg_attr(docsrs, doc(cfg(feature = "watch")))]
impl<T: DeserializeOwned + Send + Sync + 'static> Builder<T> {
pub fn watch(
&self,
debounce: core::time::Duration,
) -> std::io::Result<crate::watch::WatchHandle> {
self.watch_with(debounce, crate::watch::WatchMode::Native)
}
pub fn watch_with(
&self,
debounce: core::time::Duration,
mode: crate::watch::WatchMode,
) -> std::io::Result<crate::watch::WatchHandle> {
let Some(install) = self.install else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"this builder is tied to no config type, so a reload would \
have nowhere to install; start from the generated \
`builder()` on a `#[dynamic_config]` type",
));
};
let watched = self
.with_spec(|spec| Ok(crate::watch::Watched::from_spec(spec)))
.map_err(|error| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, error.to_string())
})?;
let reloader = self.clone();
let name = watch_name::<T>(&self.key);
let handle = crate::watch::spawn_with(
std::any::TypeId::of::<T>(),
name,
watched,
debounce,
mode,
move || {
let value = reloader.load()?;
install(value);
reloader.write_cache();
Ok(None)
},
)?;
if let Some(register) = self.register {
register(self);
}
Ok(handle)
}
}
#[cfg(feature = "watch")]
fn watch_name<T: 'static>(key: &str) -> &'static str {
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
static NAMES: OnceLock<Mutex<HashMap<std::any::TypeId, &'static str>>> = OnceLock::new();
let mut names = NAMES
.get_or_init(|| Mutex::new(HashMap::new()))
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
names
.entry(std::any::TypeId::of::<T>())
.or_insert_with(|| Box::leak(format!("builder:{key}").into_boxed_str()))
}