Convert to a trait or function pointer

I have a case where I'd like to enable users to set a resolver. This resolver can be a simple function or a struct implementing a resolver. Here's an example:

// Parameter that each resolver accepts.
struct Intent {}

// Resolver A
type Pointer = fn(Intent) -> Result<usize, usize>;

// Resolver B
trait Resolver {
    fn resolve(&self, intent: Intent) -> Result<usize, usize>;
}

// Desired final object
struct Handler<'a> {
    resolver: Option<&'a dyn Resolver>,
    pointer: Option<Pointer>,
}
impl <'a> Handler<'a> {
    fn from_resolver(resolver: &'a dyn Resolver) -> Self {
        Self { resolver: Some(resolver), pointer: None }
    }
    fn from_pointer(pointer: Pointer) -> Self {
        Self { resolver: None, pointer: Some(pointer) }
    }
}
impl <'a> From<&'a dyn Resolver> for Handler<'a> { // From anything implementing Resolver Into<Handler>
    fn from(resolver: &'a dyn Resolver) -> Handler<'a> {
        Handler::from_resolver(resolver)
    }
}
impl <'a> From<Pointer> for Handler<'a> { // From Pointer Into<Handler>
    fn from(pointer: Pointer) -> Handler<'a> {
        Handler::from_pointer(pointer)
    }
}

// Master struct accepting resolvers and converting them to Handler.
struct App<'a> {
    handler: Option<Handler<'a>>,
}
impl <'a> App<'a> {
    fn set_handler<H: Into<Handler<'a>>>(&mut self, handler: H) {
        self.handler = Some(handler.into());
    }
}

// The result I'd like is to be able to set Resolver trait or function pointer.
fn main() {
    let app = App { handler: None };

    // set structure
    struct Foo {}
    impl Resolver for Foo {
        fn resolve(&self, intent: Intent) -> Result<usize, usize> { Ok(1) }
    }
    app.set_handler(&Foo{}); // ERROR

    // or set function pointer / closure
    fn bar(i: Intent) -> Result<usize, usize> { Ok(1) }
    app.set_handler(bar); // ERROR
}

Obviously, I'm doing something wrong because I see errors on set_handler inputs.

the trait bound `Handler<'_>: std::convert::From<&main::Foo>` is not satisfied

the trait `std::convert::From<&main::Foo>` is not implemented for `Handler<'_>`

help: the following implementations were found:
        <Handler<'a> as std::convert::From<&'a (dyn Resolver + 'a)>>
        <Handler<'a> as std::convert::From<fn(Intent) -> std::result::Result<usize, usize>>>
note: required because of the requirements on the impl of `std::convert::Into<Handler<'_>>` for `&main::Foo`rustc(E0277)
main.rs(55, 9): the trait `std::convert::From<&main::Foo>` is not implemented for `Handler<'_>`
the trait bound `Handler<'_>: std::convert::From<fn(Intent) -> std::result::Result<usize, usize> {main::bar}>` is not satisfied

the trait `std::convert::From<fn(Intent) -> std::result::Result<usize, usize> {main::bar}>` is not implemented for `Handler<'_>`

help: the following implementations were found:
        <Handler<'a> as std::convert::From<&'a (dyn Resolver + 'a)>>
        <Handler<'a> as std::convert::From<fn(Intent) -> std::result::Result<usize, usize>>>
note: required because of the requirements on the impl of `std::convert::Into<Handler<'_>>` for `fn(Intent) -> std::result::Result<usize, usize> {main::bar}`rustc(E0277)

How can I achieve such functionality?

This comment is wrong. &'a dyn Resolver is not "anything implementing Resolver", it's the concrete type - the trait object, to be precise.

If you really want to allow converting every type which implements Resolver, you should specify this explicitly by using generics:

impl <'a, T> From<&'a T> for Handler<'a> where T: Resolver {
    fn from(resolver: &'a T) -> Handler<'a> {
        Handler::from_resolver(resolver as &_)
    }
}

Note the as &_ bit: this is necessary to explicitly request conversion into trait object (you could also make Handler itself generic).

As for Pointer, there's another problem here: every function has its own, unique type, which is not equal to the function pointer type, but can be coerced into it - again, using as Pointer. If you don't like this, well, you'll have to use Fn* traits and, again, generics.

Here's the playground with these fixes.

1 Like

Instead of juggling with all sorts of complicated uses of trait objects and explicitly requiring lifetimes, you could just implement the trait for all suitable functions:

impl<F: FnMut(Intent) -> Result<usize, usize>> Resolver for F {
    fn resolve(&mut self, intent: Intent) -> Result<usize, usize> {
        self(intent)
    }
}
4 Likes

Amazing, guys!

@H2CO3 This exceeds my current understanding. Would you be so kind and put it into my example so I can see how this can be used?

It means that you don't have to make a distinction between resolver "objects" and function "pointers", since it makes any function with type signature FnMut(Intent) -> Result<usize, usize> into a Resolver itself. So there's no need for a conversion. You can just start accepting any Resolver, and it will automatically work with functions too.


By the way, if you need "exactly one or the other, but not both"-style choices in the future, don't use a struct with optional fields. Use an enum instead.

3 Likes

@H2CO3 Hum, you gave me something to play with :). I can't get this to work for my case. Have you tested your solution in @Cerber-Ursi 's playground example? Can you modify it for me, please?

Sure. Unfortunately, it looks like the less conservative FnMut bound can't be made work, so Fn it is.

1 Like

Awesome! It works. I really appreciate your help!

Just for the record, here's the shortest code I can think of:

// Parameter that each resolver accepts.
pub struct Intent {}

// Resolver definition.
pub trait Resolver {
    fn resolve(&self, intent: Intent) -> Result<usize, usize>;
}
impl<F: Fn(Intent) -> Result<usize, usize>> Resolver for F {
    fn resolve(&self, intent: Intent) -> Result<usize, usize> {
        self(intent)
    }
}

// Application holding resolver of type struct or function pointer.
struct App<'a> {
    pub resolver: Option<&'a dyn Resolver>,
}
impl <'a> App<'a> {
    fn with_resolver(&mut self, resolver: &'a dyn Resolver) {
        self.resolver = Some(resolver);
    }
    pub fn resolve(&self) {
        let handler = self.resolver.unwrap();
        let res = handler.resolve(Intent{});
        println!("XXXXX: {:?}", res.unwrap())
    }
}

// Run app with two different resolvers.
fn main() {
    let mut command = App { resolver: None };

    // set structure
    struct Foo {}
    impl Resolver for Foo {
        fn resolve(&self, _: Intent) -> Result<usize, usize> { Ok(2) }
    }
    command.with_resolver(&Foo{});
    command.resolve();

    // or set function pointer / closure
    fn bar(_: Intent) -> Result<usize, usize> { Ok(3) }
    command.with_resolver(&bar);
    command.resolve();
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.