pub trait OptionExt<T> {
    fn or_else_lazy<F>(self, f: F) -> Option<T>
    where
        F: FnOnce() -> Option<T>;
    
    fn map_or_default<U: Default>(self, f: impl FnOnce(T) -> U) -> U;
    
    fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<U>;
}

impl<T> OptionExt<T> for Option<T> {
    fn or_else_lazy<F>(self, f: F) -> Option<T>
    where
        F: FnOnce() -> Option<T>,
    {
        self.or_else(f)
    }
    
    fn map_or_default<U: Default>(self, f: impl FnOnce(T) -> U) -> U {
        self.map_or_else(|| U::default(), f)
    }
    
    fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<U> {
        self.and_then(f)
    }
}

pub fn unwrap_or_default<T: Default>(opt: Option<T>) -> T {
    opt.unwrap_or_else(|| T::default())
}

pub fn option_to_result<T, E>(opt: Option<T>, err: E) -> Result<T, E> {
    opt.ok_or(err)
}