use std::error::Error;
use std::fmt::Debug;
use std::io::{Error as IoError, Result as IoResult};
use std::fmt::Display;
use std::ops::DerefMut;
type FnInit<T> = dyn Fn() -> T + Sync;
type FnInitFailable<T> = dyn Fn() -> IoResult<T> + Sync;
pub enum DefaultInit<T> {
None,
Infailable(Box<FnInit<T>>),
Failable(Box<FnInitFailable<T>>),
}
#[derive(Debug)]
pub enum InitError {
NoDefaultInitializer,
Failed(IoError),
}
pub fn or_init_with<T, F>(mut inner: impl DerefMut<Target = Option<T>>, init_fn: F) -> T
where
T: Clone,
F: FnOnce() -> T,
{
match inner.as_ref() {
Some(existing) => existing.clone(),
None => inner.insert(init_fn()).clone(),
}
}
pub fn or_try_init_with<T, E, F>(
mut inner: impl DerefMut<Target = Option<T>>,
init_fn: F,
) -> Result<T, E>
where
T: Clone,
F: FnOnce() -> Result<T, E>,
{
match inner.as_ref() {
Some(existing) => Ok(existing.clone()),
None => match init_fn() {
Ok(value) => Ok(inner.insert(value).clone()),
Err(error) => Err(error),
},
}
}
impl<T> Debug for DefaultInit<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::None => write!(f, "None"),
Self::Infailable(_) => write!(f, "Infailable"),
Self::Failable(_) => write!(f, "Failable"),
}
}
}
impl Display for InitError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InitError::NoDefaultInitializer => write!(f, "No default initializer available!"),
InitError::Failed(error) => Display::fmt(&error, f),
}
}
}
impl Error for InitError {}