Hi,
I have the following code:
struct EventA {
foo: String,
}
struct EventB {
bar: String,
}
enum EventHandler<FNW, ARGW>{
EventA(FNW<Box<dyn Fn(ARGW<EventA>) + Send + Sync + 'static>>),
EventB(FNW<Box<dyn Fn(ARGW<EventB>) + Send + Sync + 'static>>),
}
(There are around 150 event types that I generate automatically from a JSON file.)
(Here is a Playground with the code from this post)
But the compiler rejects this with "type argument not allowed":
error[E0109]: type arguments are not allowed for this type
--> src/bin/main.rs:15:16
|
15 | EventA(FNW<Box<dyn Fn(ARGW<EventA>) + Send + Sync + 'static>>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type argument not allowed
Is there any way I can do this?
Here is what I try to archive with the code above:
EvenHandler is a wrapper of event callbacks (so a user of my crate can store callbacks for different events in a collection).
The first type parameter (FNW) is a wrapper for the boxed closure, so a user can select a collection type (this is useful if there are several callbacks for the same event):
// tupple
let _ = EventHandler::EventA((
|_: Rc<EventA>| (),
|_: Rc<EventA>| (),
));
// array
let _ = EventHandler::EventA([
|_: Rc<EventA>| (),
|_: Rc<EventA>| (),
]);
// custom struct
let _ = EventHandler::EventA(MyEventHandles {
internal: |_: Rc<EventA>| (),
external: |_: Rc<EventA>| (),
});
Here my first problem arises:
I'd also like to support the usage of a HashMap (and similar types), but HashMaps have two type arguments (or even 3, I'm not 100% sure...).
I tried the following, but that results in a syntax error:
let event_a_handlers = HashMap::new();
event_a_handlers.insert("foo", |_: Rc<EventA>| ());
event_a_handlers.insert("bar", |_: Rc<EventA>| ());
let _ = EventHandler::EventA::<HashMap<String, _>(event_a_handlers);
(I was hoping, that I could pass a type parameter that has itself one type parameter missing that the compiler will insert later.)
Is it somehow possible to archive this without an additional KeyValueEventHandler type that has two type parameters?
My second problem is regarding the second type parameter ARGW:
EventA(FNW<Box<dyn Fn(ARGW<EventA>) + Send + Sync + 'static>>)
As mentioned, the compiler rejects this type parameter with "type argument not allowed" – how can I archive this?
I need this type parameter so users can wrap the argument of the callback if needed. For example, I need (in another crate that uses this crate) to wrap the parameter in a Rc, but others might need to wrap it in an Arc or something completely different:
// `Rc`
let _ = EventHandler::EventA((
|_: Rc<EventA>| (),
|_: Rc<EventA>| (),
));
// `Arc`
let _ = EventHandler::EventA((
|_: Arc<EventA>| (),
|_: Arc<EventA>| (),
));
I also was hoping, that I somehow can support that event callbacks can accept / request references to the events (instead of owned values).
It seems AsRef could be used for this:
let _ = EventHandler::EventA((
|_: dyn AsRef<EventA>| (),
|_: dyn AsRef<EventA>| (),
))
But I don't like this option very much because now the user has to call as_ref() to get the actual reference.
And last:
Many users of my crate (if there will be any
...) probably don't need to wrap the boxed closure and/or the argument of the closure in another type.
Because of that, I'd like to offer this option as well.
At the moment I think my only option is to create additional types that don't have these type parameters, which would mean 3 additional types.
Therefore I wonder if there is any way the following would be possible with EventHandler from above:
let _ = EventHandler::EventA(|_: EventA| ());
(To me it seems this is not possible, but maybe someone has an idea how this would be possible).
I feel, if I want to offer everything that a user could need, I need to generate 20 different types, which would IMO result in a shitty API.
I'd be thankful for every tip or hint, even for completely different approaches! ![]()
Here is again the link to the Playground, if someone wants to give it a try.