I have a function with return type Option<Result<T, E>> where

each function is a 'rule'

None = this rule is not relevant, try next rule

Some(Ok(..)) = applied rule, got result

Some(Err(..)) = applied rule, got error

fn foo(...) -> Option<Result<T, E>> {
let x = ... ?; // returns None if it doesn't match.
let y: Result<T2, E> = blah(x);
let z: T2 = y?; // if y is an E, let's return Some(Err(E))
// is this line possible? The best I can think of is:
match y {
Err(e) => return Some(Err(e)),
(Ok(z) => ...
}
// but I don't like this 'solution', as I actually have:
let y1: Result<T2, E> = blah(x);
let y2: Result<T3, E> = foobar(x);
/// ... and more
}

Am I basically forced to create two functions here?

let z: T2 = match y.transpose() {
Err(e) => return Some(Err(e)),
Ok(v) => v,
};

But this would be made much easier if all of your functions returned Result<Option<T>, E> rather than Option<Result<T, E>>. Is there a reason you chose the latter over the former?

Edit: ahh, I just realized that Option being the outer type makes let x = ... ? actually work.

I don't know of a way to have niceness for both returning None on None and returning Some(Err) on Some(Err). Would it be at all reasonable to just return a Result<T, E> and have your error type contain a variant for "rule not relevant", maybe with some combinator functions for ignoring it?