typed_env/
error_reason.rs

1use std::sync::Mutex;
2
3pub struct ErrorReason {
4    error_provider: Mutex<Option<Box<dyn 'static + Sync + Send + FnOnce() -> String>>>,
5    reason_str: std::sync::OnceLock<String>,
6}
7
8impl std::fmt::Debug for ErrorReason {
9    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10        write!(f, "ErrorReason({:?})", self.as_str())
11    }
12}
13
14impl std::fmt::Display for ErrorReason {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        write!(f, "{}", self.as_str())
17    }
18}
19
20impl ErrorReason {
21    pub fn new(producer: impl 'static + Sync + Send + FnOnce() -> String) -> Self {
22        Self {
23            error_provider: Mutex::new(Some(Box::new(producer))),
24            reason_str: std::sync::OnceLock::new(),
25        }
26    }
27
28    pub fn as_str(&self) -> &str {
29        let result = self
30            .reason_str
31            .get_or_init(|| match self.error_provider.lock() {
32                Err(e) => {
33                    panic!(
34                        "typed-error internal error: cannot lock to get error provider: {}",
35                        e
36                    );
37                }
38                Ok(mut error_producer) => {
39                    let error_producer = error_producer.take();
40                    match error_producer {
41                        None => panic!("typed-error internal error: provider has been consumed"),
42                        Some(error_producer) => (error_producer)(),
43                    }
44                }
45            });
46
47        result.as_str()
48    }
49}