Implementing convenience trait on Result, fails when non-generic

The tl;dr: I want to add a convenience method to convert Result<(), ump::Error<MyError>> to ControlFlow<MyError, ()>.

Given the trait:

trait ToControlFlow {
  fn to_ctrlflow(self) -> ControlFlow<MyError, ()>;
}

Why does this not work:

impl ToControlFlow for Result<(), ump::Error<MyError>> {

.. while this does?

impl<E> ToControlFlow for Result<(), E> {

(Given that E indeed is ump::Error<MyError>)

I get the error:

error[E0599]: no method named `to_ctrlflow` found for enum `Result` in the current scope
  --> src/main.rs:37:18
   |
37 |   rctx.reply(42).to_ctrlflow()
   |                  ^^^^^^^^^^^ method not found in `Result<(), Error<MyError>>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `ToControlFlow` defines an item `to_ctrlflow`, perhaps you need to implement it

Minimal test case main.rs, used with ump = "0.10.2":

use std::ops::ControlFlow;

#[derive(Debug, PartialEq)]
pub enum MyError {
  Internal
}

/// Convenience trait used to map `Result<(), ump::Error<MyError>>` to
/// `ControlFlow<MyError, ()>`.
trait ToControlFlow {
  fn to_ctrlflow(self) -> ControlFlow<MyError, ()>;
}

// Why doesn't this work?
//impl ToControlFlow for Result<(), ump::Error<MyError>> {
impl<E> ToControlFlow for Result<(), E> {
  fn to_ctrlflow(self) -> ControlFlow<MyError, ()> {
    self.map_or_else(
      |_| ControlFlow::Break(MyError::Internal),
      |_| ControlFlow::Continue(())
    )
  }
}

fn main() {
  let (server, _client) = ump::channel::<u32, u32, MyError>();
  let _ = service(server);
}

fn service(
  server: ump::Server<u32, u32, MyError>
) -> ControlFlow<MyError, ()> {
  let (_msg, rctx) = server.wait().unwrap();

  // .reply() returns `Result<(), ump::Error<E>>`, and E is `MyError` here.
  rctx.reply(42).to_ctrlflow()
}

If you specify what you think the return type of rctx.reply(...) is, you'll see the problem

error[E0308]: mismatched types
  --> src\bin\main.rs:33:48
   |
33 |     let err: Result<(), ump::Error<MyError>> = rctx.reply(42);
   |              -------------------------------   ^^^^^^^^^^^^^^ expected `ump::Error<MyError>`, found `ump::rctx::err::Error<MyError>`
   |              |
   |              expected due to this
   |
   = note: expected enum `Result<_, ump::Error<MyError>>`
              found enum `Result<_, ump::rctx::err::Error<MyError>>`

The actual error type is ump::rctx::err::Error<MyError>. The rctx module is private and I didn't see any re-exports for the error type, so unfortunately I don't think you can name that error type in the impl.

1 Like