Event Manager Design Question

I want to make an event manager for a game, but am having trouble storing functions in a vec. I'm seeing there are receivers and channels. Would that be a good place to look, or is there something else? Any libraries?

Can you share what did you try with us?

1 Like

Yep ty, this was the gist of it:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a47e79ef3f1f2d12e3668fe611f21c94

use std::collections::HashMap;

enum EventType {
    Jump,
    Move,
    //...
}

struct EventManager<T> where T: Fn() {
    events: HashMap<EventType, T>
}

fn main() {
    let mut em = EventManager {
        events: HashMap::<EventType, Fn()>::new()
    };
}

which complains about the Fn size not being known at compile time. I'd rather not mess with dynamics or lifetimes if I can help it, and a channel recevier seemed to be a good alternative to what I was trying to do

https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html

edit: Also am planning on trying it out, but wanted to see if there were alternatives first

What will you store in the hashmap as an value? Just plain functions or also closures?

1 Like

They can just be functions. I'll be passing in a ref to a structure with game data

Note that Fn() is not a type. It is a trait for all functions that at most borrow immutable state. Its relatives are FnMut() (for functions that borrow mutable state) and FnOnce() (for functions that consume their environment by-value). You can't use these as types directly, exactly because they are not types. You can make them use dynamic dispatch by creating a trait object, e.g. Box<dyn Fn()>.


For plain function pointers, just use fn().

3 Likes

well that at least got that code to compile. ty

But, obviously, it does not accept a type like fn(i32). Is there any way we can make T in the EventManager<T> generic over any callable type without restricting function signature?

Do you mean that you want to store functions of any possible argument and return types (possible heterogeneous), in the same collection? I don't think that's possible, nor that it should be done. What do you need that for? How would you be able to call them without statically knowing their type?

No, I don't mean that. I wonder if it is possible for T to be generic over any callable -or more specially over any Fn regardless of the return type, parameter type and the parameter count- like how it does be generic over any Iterable in a context like struct MyStruct<I, T: Iterator<Item=I>>. The problem is that, for example, Fn may have any number of parameters but something like struct MyStruct<A, R, T: Fn(A) -> R> only have one parameter, A.

Hm, no, I don't think that's possible today. For truly allowing multiple arguments, something like variadic generics would be necessary (which is being worked on or at least discussed, but it's not nearly there).

As a workaround, you can keep the definition of MyStruct as you described above, and pass tuples to functions that require multiple arguments.

1 Like

Tuples seems a good way of implementing it if necessary, thanks.

Are function traits special in a sense that they have a different, function signature-like syntax and can have arbitrary numbers of parameters? I don't think I can, as a language user, define a similar trait. Can I? Is it a special part of language and not available for general use?

Yes, they are special in that regard. It is also not possible to implement them currently, but that is a nightly feature and it may be stabilized one day.

1 Like

Internally each Fn trait is a trait with Args as a type parameter (intended to be a tuple) and Output as an associated type. But these details are indefinitely unstable/internal implementation details hidden behind the parenthetical notation, as noted in the error output in this example. So you could be generic over parameter types and return type using the parenthetical notation, but not parameter count.

Relevant comment regarding unstableness and variadics.

Edit: More information on the indefinitely unstable aspect can be found in this issue.

1 Like