2

I replaced fn(x) -> y typing with FnMut(x) -> y according to my needs and according to what was suggested for me here. But I got another error:

trait objects must include the dyn keyword

This is minimal sandbox that reproduces the error.

I tried to investigate the issue. So, I found this. After that I tried to add dyn. But since I got error that size in not known at compile time, I also tried to add Box to typing like:

-> vector<Box<dyn FnMut(HandlerInput) -> Result<HandlerResponse, Error>>>

and after that tried to wrap handlers with Box::new(), but still have no success. I feel like I do something wrong.

Could somebody explain me how to fix this issue ? Maybe dyn not what I should use ? (I also tried to use impl instead, but this not helped)

Sergio Ivanuzzo
  • 1,820
  • 4
  • 29
  • 59
  • 3
    `FnMut` -> `dyn FnMut` -> `Box` is the correct set of changes to get you on your way. You should post your version with that and then show your problems. I see you've only partially applied other suggestions from your last post (changed the function type to `FnMut(&mut HandlerInput)` but did not change your `handler1`, `handler2`, etc functions) – kmdreko Jun 08 '22 at 16:23
  • Besides that, your playground is far from being minimal. If you want to locate errors, you really have to make a **small** example where the error occurs. – jthulhu Jun 08 '22 at 16:29
  • @kmdreko thank you for comment, could you please look https://stackoverflow.com/questions/72549399/expected-a-fnmutx-closure-found-dyn-forr-s-fnmutr-mut-xs ? – Sergio Ivanuzzo Jun 08 '22 at 16:44
  • 1
    @SergioIvanuzzo Here is a [fixed version](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=25c3f49a4f30872bed38236868ae74d3) of your example with some minor refactoring to improve safety/usability. However it likely still won't work because `handle_read` can't tell where one packet ends and the next begins. It just returns whatever data has been buffered by the OS. You may want to consider something like prefixing packets with their lengths so you can distinguish between them. – Locke Jun 08 '22 at 17:30
  • @Locke thank you very much ! If you add your comment as answer I will accept it – Sergio Ivanuzzo Jun 09 '22 at 02:08

1 Answers1

3

You probably don't know, but there is a huge difference between fn(x) -> y and FnMut(x) -> y: the former is a type (basically, it's a pointer to a function), while the second is a trait. This means that you can't switch the one for the other. Fortunately, there is a way (actually, multiple ways) to tell Rust that you want to accept any type that implements a given trait. One of these is trait objects, whose syntax is dyn Trait where Trait is a trait.

Trait objects

Traits objects use dynamic dispatch, which means that Rust allows any type that implements a given trait Trait to be passed where a dyn Trait was expected, and the information about where the different methods are found for a given value of type dyn Trait is provided by runtime information (ie. that value also has a little table included providing that information). This means that, for instance, Rust cannot know the size of dyn Trait at compile time, simply because it could be any value, as long as its type implements Trait. For this reason, you need to allocate it on the heap, and pass a pointer to the allocated data instead. This is the job of Box.

The solution is therefore to replace any occurence of Trait as a type declaration with Box<dyn Trait> (in your case, Box<dyn FnMut(HandlerInput) -> Result<HandlerResponse, Error>>>) and make the appropriate changes (ie. (un)box your closures).

jthulhu
  • 7,223
  • 2
  • 16
  • 33