Handy way to convert a `fn` function pointer to an Fn closure?

I recently learned how function pointers are not really the same as closures. Makes sense really.

But I am trying to create a collections of closures that can be called depending on some conditions.

I think it would be handy to add an entry to the collection by either supplying an anonymous function or a compiled function.

Storing closures doesn't seem too bad but is there any way of quickly converting/wrapping a function pointer into a closure ? I'm currently running into a bunch of errors like

expected trait std::ops::Fn, found fn item.

Here is a quick code snippet where I'm building my collection and trying to insert

type TMBHandler = dyn Fn() -> std::result::Result<(), String>;

fn create_handler_mappings() -> HashMap<u32, Box<TMBHandler>> {
    let res = HashMap::new();

    let x = &handle_null_message;
    res.insert(MessageType::to_number(MessageType::Null), Box::new(handle_null_message));

    return res; // Outputs the error above
}

fn handle_null_message(msg: &TransportMessageBlock, session: &ServerSession, ctx: &ServerContext) -> std::result::Result<(), String> {
    return Ok(());
}

Can that be possible ? I know I can probably create closures that just calls the function but given the signature of the closure it would be quite verbose. Is there some shorthand way of wrapping a fn pointer into an Fn (or FnOnce) object ?

try this (add the closure indication: ||):

 res.insert(MessageType::to_number(MessageType::Null), Box::new( || handle_null_message));

A Box<fn> can be coerced directly to a Box<dyn Fn>, but this needs to be a separate step from the Box::new call. Right now your map type will be inferred as holding the Box<fn> type, so it might be enough to just give it an explicit type when you create it.

2 Likes

Ah, this was the issue. Thank you very much !

FYI the code was transformed into this and it worked. Giving a specific type to the fn Box was enough to nudge the compiler in the right direction.

fn create_handler_mappings() -> HashMap<u32, Box<TMBHandler>> {
    let mut res = HashMap::new();

    let x: Box<TMBHandler> = Box::new(handle_null_message);
    let y: Box<TMBHandler> = Box::new(handle_simple_message);

    res.insert(MessageType::to_number(MessageType::Null), x);
    res.insert(MessageType::to_number(MessageType::Simple), y);

    return res;
}
2 Likes