f:F, where F: FnOnce(&mut [u8]) vs f: &mut dyn FnMut(&[u8]

I'm reading some code and it has a consume function which makes it possible for me to pass my own f which will tell what to do with the buffer. This is good for preventing copies.

fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
    where
        F: FnOnce(&mut [u8]) -> Result<R>,

I did the same to my code, but like this:

pub fn phy_receive(
        &mut self,
        f: &mut dyn FnMut(&[u8])
    ) -> u8 {

and to be fair I don't know what is the difference, aside from FnOnce vs FnMut. But what is the difference of using a dyn vs a generic to specify this function?

The behavior is bascally the same, but they are compiled differently, and the differences can affect their run-time performance.

Each time your code calls the generic function with an argument of a different type, the compiler will generate a new copy of the generic function specialized for that type. This often improves performance, at the cost of larger binary size.

In contrast, the function that takes dyn Trait only gets compiled once, which will make your generated code smaller. But it might also be slower because it has to call the function through a pointer (adding a small amount of overhead), and the passed function generally can't get inlined into the caller (which may prevent other optimizations from happening).