pub trait OptionInsertExt<T> {
fn get_or_try_insert_with<F, E>(&mut self, f: F) -> Result<&mut T, E>
where
F: FnOnce() -> Result<T, E>;
}
impl<T> OptionInsertExt<T> for Option<T> {
#[inline]
fn get_or_try_insert_with<F, E>(&mut self, f: F) -> Result<&mut T, E>
where
F: FnOnce() -> Result<T, E>,
{
if let None = *self {
*self = Some(f()?);
}
match self {
Some(v) => Ok(v),
None => unsafe { core::hint::unreachable_unchecked() },
}
}
}
#[cfg(test)]
mod tests {
use super::OptionInsertExt;
#[test]
fn it_works_when_some() {
let mut opt = Some(0);
*opt.get_or_try_insert_with::<_, ()>(|| Ok(3)).unwrap() += 1;
*opt.get_or_try_insert_with::<_, ()>(|| Err(())).unwrap() += 1;
assert_eq!(opt, Some(2));
}
#[test]
fn it_works_when_none() {
let mut opt = None;
opt.get_or_try_insert_with::<_, ()>(|| Ok(1)).unwrap();
assert_eq!(opt, Some(1));
}
#[test]
fn it_errors() {
let mut opt: Option<i32> = None;
assert_eq!(opt.get_or_try_insert_with(|| Err(())), Err(()));
}
}