#event-handling #async #macro #derive #proc-macro #generate

macro event_bridge

A procedural macro library for generating event handlers

2 releases

0.3.1 Dec 6, 2024
0.3.0 Dec 6, 2024

#401 in Procedural macros

Download history 243/week @ 2024-12-02 49/week @ 2024-12-09

292 downloads per month

MIT license

11KB
113 lines

event_bridge

Pipeline Status Crates.io

A procedural macro that generates asynchronous event handlers from enum definitions, automatically dispatching enum variants to associated trait methods. This reduces boilerplate and simplifies the integration between synchronous UI events and asynchronous backend logic.

Motivation

In many applications, especially those with graphical user interfaces (GUIs), input from the UI thread must be forwarded to asynchronous backend services or controllers. Writing repetitive match expressions to route each event to its corresponding async API method can be tedious and error-prone.

event_bridge streamlines this process. By annotating your event enum with a custom procedural macro, you automatically get an async event handler method that matches each variant and calls the appropriately named method on your specified API trait.

How It Works

When you apply the #[derive(EventBridge)] macro to your event enum, it generates a forward_to method that:

  • Consumes your event (the enum variant).
  • Matches the event variant to the corresponding async trait method based on variant naming.
  • Calls the trait method with the extracted fields from the enum variant.
  • Returns the specified return type of the trait methods.

This significantly reduces the boilerplate involved in writing match arms and manually forwarding arguments for each new event added to your application.

Installation

Add event_bridge and async-trait to your Cargo.toml:

[dependencies]
event_bridge = "0.1.0"
async-trait = "0.1"

Quick Start

use async_trait::async_trait;
use event_bridge::EventBridge;
use std::sync::Arc;
use tokio::sync::Mutex;

// Define a custom error type for demonstration
type MyReturnType = Result<(), String>;

// Define an event enum and associate it with a trait and error type
#[derive(EventBridge)]
#[forward_to_trait(MyApiTrait)]
#[trait_returned_type(MyReturnType)]
pub enum Event {
  SetValue(i32),
  SetName(String),
  Initialize,
}

// Define the API trait that corresponds to the event variants
#[async_trait]
pub trait MyApiTrait {
  async fn set_value(&mut self, value: i32) -> MyReturnType;
  async fn set_name(&mut self, name: String) -> MyReturnType;
  async fn initialize(&mut self) -> MyReturnType;
}

// Example usage
#[tokio::main]
async fn main() {
  // Assume `MyApiImpl` implements `MyApiTrait`
  let mut api_impl = MyApiImpl::new();

  // Example event to dispatch to the API implementation
  let some_event = Event::SetValue(42);

  // Dispatching an event becomes straightforward:
  let result = some_event.forward_to(&mut api_impl).await;
}

Configuration

The macro supports two attributes on the enum:

  • #[forward_to_trait(TraitName)] (required)

    Specifies the trait that defines the async methods corresponding to each enum variant.

  • #[trait_returned_type(ReturnType)] (optional)

    Specifies the return type returned by the generated event handler. If omitted, the handler defaults to ().

Supported Variants

The macro handles various enum variants:

#[derive(EventBridge)]
#[forward_to_trait(Handler)]
enum Event {
  NoArgs,                      // Unit variant
  SingleArg(String),           // Single argument
  MultipleArgs(i32, String),   // Multiple arguments
  NamedFields { id: i32 },     // Named fields
}

Each variant must correspond to a method in the specified trait. The method name is derived from the variant name converted to snake_case, and the method arguments match the variant’s fields in order and type.

Error Handling

Ensure that your trait methods return the appropriate type to maintain consistency.

License

This project is licensed under the MIT license.

Contributing

Contributions, issues, and pull requests are welcome. Feel free to open a discussion on GitHub if you have any questions or suggestions.

Dependencies

~225–670KB
~16K SLoC