Pauan / rust-dominator

Zero-cost ultra-high-performance declarative DOM library using FRP signals for Rust!
MIT License
967 stars 62 forks source link

Event Queue #26

Closed dakom closed 4 years ago

dakom commented 4 years ago

What's the recommendation for storing events in a queue to be processed later?

Box<dyn StaticEvent> is not allowed since StaticEvent can't be made into a Trait Object

Pauan commented 4 years ago

What's your use case?

dakom commented 4 years ago

Game loop such as http://www.isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing

So all input events are collected and handled on the next tick, rather than immediately.

Pauan commented 4 years ago

You have a few options:

  1. You can use Box<dyn Any> and then the downcast_ methods to convert it back into a concrete type. I don't recommend this though.

    It's slow, rather clunky to work with, and error prone (only runtime type checking, no exhaustiveness checks).

    I would only use this if I needed to support all arbitrary events (rather than a fixed number of event types). And even then I wouldn't like it.

  2. Create a new trait with the methods you need, and then impl it for the event types. This is really not recommended.

    It has the same downsides as Any, and in addition it only works if all the event types share the same methods, so it's very inflexible.

  3. You can create an enum:

    enum Event {
       MouseMove(events::MouseMove),
       MouseClick(events::Click),
       KeyDown(events::KeyDown),
       // ...
    }

    Or better yet, use semantically appropriate enum fields:

    enum Event {
       MouseMove {
           x: i32,
           y: i32,
       },
       MouseClick {
           x: i32,
           y: i32,
           button: events::MouseButton,
       },
       KeyDown {
           key: String,
           ctrl: bool,
           shift: bool,
           alt: bool,
       },
       // ...
    }

    This is what I recommend. It's very fast, it's zero allocation (no need for Box, just store it directly), it's extremely flexible, it's statically type safe, it gives you a more Rust-y type to work with (including exhaustive pattern matching), and it allows you to do some pre-processing of the events before converting them into an Event.

    This is what I use in tab-organizer to merge many events into a single queue. As a bonus, if you use serde you can easily derive Serialize/Deserialize on the Event struct, so this technique works for sending events between the client/server, or storing events in a database.