Feature Request: add `EnumIsAnd` and `EnumIsOr` derive macros
The EnumIs macro is extremely useful, and I think it'd improve ergonomics ever more if strum generated is_*_and and is_*_or methods which allow for chaining conditional comparisons.
One use-case where this is useful is for error enums, especially nested error enums:
#[derive(Debug, thiserror::Error, strum::EnumIs, strum::EnumIsAnd, strum::EnumIsOr)]
enum AppError {
#[error("i/o error: {0:?}")]
Io(#[from] std::io::Error),
#[error("unknown error: {0:?}")]
Unknown(String),
}
fn foo() -> Result<(), AppError> {
let f = std::fs::File::create("foo.txt")?;
f.write_all(b"Hello, world!")?;
Ok(())
}
fn main() {
match foo() {
Ok(_) => {
info!("success");
}
Err(err) => {
if err.is_io_and(|io_err| match io_err.kind {
/// Can handle specific I/O errors differently
) {
/// Do something
}
}
}
The idea is to have more ergonomic and readable error handling code when matching on outer error types based on the inner error type.
This functionality can be extensions on the existing EnumIs macro, or entirely separate macros (i.e. EnumIsAnd, EnumIsOr), depending on what makes more sense architecturally.
Happy to work on this and raise a PR, if you think it's useful enough to include in strum and maintain.
Since let-chains were stabilized in 1.85, I think they're more readable for this purpose than a new method for every variant:
if let AppError::Io(io_err) = err && match io_err.kind /* ... */
vs
if err.is_io_and(|io_err| match io_err.kind