this repo has no description
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}