So the problem you hit here is that function types are different from function pointer types. The error message talks about the type “fn() -> std::result::Result<(), std::io::Error> {default_function}” which is a compiler-errors-message way of saying “the type of default_function which happens to be a function without parameters returning Result<(), io::Error>”.
It is important to know in this context that each and every function in Rust has it’s own unique type which has the effect that passing a function to something like Iterator::map will get specialized and properly inlined. Functions are similar to non-capturing closures in this way. Another similarity between the two is that both can be coerced into function pointers, e.g. with as.
It’s a bit unfortunate that there’s currently no trait that expresses “type T can be coerced into type S”. A possible workaround, using unsafe code, could be to check for a zero-sized and Copy type that implements Fn. Playing around in a playground got me something like this. This could be used to implement your trait. It seems difficult to also still support function pointers without specialization.
Here’s how to integrate my playground into yours (I haven’t fixed warnings on public/private issues): (LINK)
Edit: One should probably also add a F: 'static bound to the ZeroSizedFunction implementation for good measure. I’m not sure if it might me unsound otherwise. Also, with Edit2: It would be possible if 'static in place it might become possible to use TypeId to also handle the function-pointer case.TypeId::of was a const fn. Without that I don’t see how to keep nice compile-time errors for trying to use non-conforming types. (It’s still possible to write an implemenation supporting both function types and function pointer types that only creates a runtime panic if used with closures that capture anything (relevant)).