Skip to content

Instantly share code, notes, and snippets.

@cgwalters
Last active July 5, 2022 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cgwalters/6a3941e83731265957270cbe83dd33e2 to your computer and use it in GitHub Desktop.
Save cgwalters/6a3941e83731265957270cbe83dd33e2 to your computer and use it in GitHub Desktop.
try_or_else
#![feature(try_trait_v2)]
use anyhow::Result; // 1.0.57
use core::ops::Try;
trait TryOrElse<T> {
fn try_or_else<R: Try<Output = T>, F: FnOnce() -> R>(self, f: F) -> R;
}
// Proposed new API for Option https://github.com/rust-lang/libs-team/issues/59
// This would actually use `self` there of course.
impl<T> TryOrElse<T> for Option<T> {
fn try_or_else<R: Try<Output = T>, F: FnOnce() -> R>(self, f: F) -> R {
if let Some(v) = self {
Try::from_output(v)
} else {
f()
}
}
}
impl<T, E> TryOrElse<T> for Result<T, E> {
fn try_or_else<R: Try<Output = T>, F: FnOnce() -> R>(self, f: F) -> R {
match self {
Ok(t) => R::from_output(t),
Err(_) => f(),
}
}
}
#[test]
fn test_option() -> Result<()> {
let o = Some("foo".to_string());
let n: Option<String> = None;
// Tests with Result; https://github.com/rust-lang/libs-team/issues/59
assert_eq!(
o.clone().try_or_else(|| std::fs::read_to_string("/"))?,
"foo"
);
assert_eq!(
n.clone()
.try_or_else(|| -> anyhow::Result<_> { Ok("fallback".to_string()) })?,
"fallback"
);
assert!(n.clone().try_or_else(|| anyhow::bail!("oops")).is_err());
// Tests that replicate or_else https://doc.rust-lang.org/std/option/enum.Option.html#method.or_else
assert_eq!(
o.clone().try_or_else(|| Some("fallback".to_string())),
Some("foo".to_string())
);
// Fallback must be lazy
assert_eq!(
o.clone()
.try_or_else(|| -> Option<String> { unreachable!() }),
Some("foo".to_string())
);
assert_eq!(
n.clone().try_or_else(|| Some("fallback".to_string())),
Some("fallback".to_string())
);
assert_eq!(n.clone().try_or_else(|| None), None);
Ok(())
}
#[test]
fn test_result() -> Result<()> {
let s = Ok::<_, std::io::Error>("foo".to_string());
let e = Err(anyhow::anyhow!("Oops"));
// Tests with Result; https://github.com/rust-lang/libs-team/issues/59
assert_eq!(s.try_or_else(|| None), Some("foo".to_string()));
assert_eq!(e.try_or_else(|| Some("foo")), Some("foo"));
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment