this repo has no description
at main 2.4 kB view raw
1//! Define `ConfigValue` & helpers 2 3use std::fmt::Display; 4use std::ops::Deref; 5use std::pin::Pin; 6use std::sync::OnceLock; 7 8/// A struct which acts like a `OnceLock` but with async support 9pub struct ConfigValue<T> { 10 inner: Inner<T>, 11} 12 13enum Inner<T> { 14 Sync { 15 lock: OnceLock<T>, 16 func: fn() -> T, 17 }, 18 Async { 19 lock: OnceLock<T>, 20 func: fn() -> Pin<Box<dyn Future<Output = T>>>, 21 }, 22} 23 24impl<T> ConfigValue<T> { 25 /// create a new synchronous ConfigValue 26 /// 27 /// this is the same as a OnceLock basically 28 pub const fn new_sync(func: fn() -> T) -> ConfigValue<T> { 29 ConfigValue { 30 inner: Inner::Sync { 31 lock: OnceLock::new(), 32 func, 33 }, 34 } 35 } 36 37 /// create a new async based ConfigValue 38 pub const fn new_async(func: fn() -> Pin<Box<dyn Future<Output = T>>>) -> ConfigValue<T> { 39 ConfigValue { 40 inner: Inner::Async { 41 lock: OnceLock::new(), 42 func, 43 }, 44 } 45 } 46 47 /// get the value. if the value is uninitialized, initialize it 48 pub async fn get(&self) -> &T { 49 match &self.inner { 50 Inner::Sync { lock, func } => lock.get_or_init(func), 51 Inner::Async { lock, func } => { 52 if let Some(val) = lock.get() { 53 return val; 54 } 55 let res = func().await; 56 let _ = lock.set(res); 57 lock.wait() 58 } 59 } 60 } 61 62 /// same as `get` but discards the result 63 /// this should be called in main to make sure that values are properly initialized before deref 64 pub async fn init(&self) { 65 let _ = self.get().await; 66 } 67} 68 69impl<T> Deref for ConfigValue<T> { 70 type Target = T; 71 fn deref(&self) -> &Self::Target { 72 match &self.inner { 73 Inner::Sync { lock, func: _ } => lock.wait(), 74 Inner::Async { lock, func: _ } => lock.wait(), 75 } 76 } 77} 78 79impl<T> Display for ConfigValue<T> 80where 81 T: Display, 82{ 83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 84 self.deref().fmt(f) 85 } 86} 87 88#[macro_export] 89/// initializes all values passed in. useful to batch init without tons of .init values 90macro_rules! init { 91 ( $( $x:expr ),* ) => { 92 $( 93 $x.init().await; 94 )* 95 }; 96}