I previously suggested an approach involving an uninhabited closure type, and a helper function which can make the call both shorter and arguably more efficient (since the Option<…>
becomes zero-sized).
Applied to this case, and updated to work with edition 2021, it looks something like
#[inline]
pub fn nop<T>() -> Option<impl FnMut(T) -> Result<(), Box<dyn Error>>> {
enum Void {}
None::<Void>.map(|void| move |_: T| {
let _ = &void; // edition 2021 closure capture workaround
match void {}
})
}
fn main() -> Result<(), Box<dyn Error>> {
let ncb = |_n: Node| -> Result<(), Box<dyn Error>> { Ok(()) };
let wcb = |_w: Way| -> Result<(), Box<dyn Error>> { Ok(()) };
let rcb = |_r: Relation| -> Result<(), Box<dyn Error>> { Ok(()) };
map_all(Some(ncb), None::<fn(_) -> _>, Some(rcb))?;
map_all(Some(ncb), nop(), Some(rcb))?; // shorter to call, and the type is smaller :-)
Ok(())
}
Depending on the use-case, i.e. on how these closures are used, in case that None
is merely handled by doing nothing whilst the Some
case has the closure called, you might also be able to avoid the need for Option
entirely, instead just expecting the user to pass some no-op closure (possibly aided by a similar convenience function if that’s considered nicer than having to write the closure manually).
If the choice between Some
vs. None
does change behavior in different ways, this would not work of course.