bevy_enum_event 0.1.0

General-purpose enum to Bevy event conversion macro - generates event types from enum variants with support for data-carrying variants
Documentation

bevy_enum_event

General-purpose enum to Bevy event conversion macro.

Overview

bevy_enum_event provides a derive macro that automatically generates Bevy event types from enum variants. For each variant in your enum, it creates a corresponding event struct organized in a snake_case module. Supports unit variants, tuple variants, and named field variants.

Bevy Compatibility

Bevy bevy_enum_event
0.17 -
0.16 0.1

Features

  • Automatic event generation: One macro generates all variant events
  • Support for data-carrying variants: Enum variants can contain data (tuple or named fields)
  • Snake case module: PlayerStateplayer_state module
  • Zero boilerplate: No manual event struct definitions needed
  • Type-safe: Each variant gets its own distinct event type
  • Generic-friendly: Works with lifetimes, generic parameters, and where clauses
  • Bevy integration: Generated events work seamlessly with Bevy's observer system
  • Deref support (optional): Automatic Deref and DerefMut for single-field variants, or multi-field variants when you tag one field with #[enum_event(deref)]

Installation

[dependencies]

bevy_enum_event = "0.1"

Quick Start

Unit Variants

use bevy::prelude::*;
use bevy_enum_event::EnumEvent;

#[derive(EnumEvent, Clone, Copy, Debug)]
enum PlayerState {
    Idle,
    Running,
    Jumping,
}

This automatically generates:

pub mod player_state {
    use bevy::prelude::Event;

    #[derive(Event, Clone, Copy, Debug)]
    pub struct Idle;

    #[derive(Event, Clone, Copy, Debug)]
    pub struct Running;

    #[derive(Event, Clone, Copy, Debug)]
    pub struct Jumping;
}

Variants with Data

use bevy::prelude::*;
use bevy_enum_event::EnumEvent;

#[derive(EnumEvent, Clone)]
enum GameEvent {
    PlayerSpawned(Entity),
    ScoreChanged { #[enum_event(deref)] player: Entity, score: i32 },
    GameOver,
}

This generates:

pub mod game_event {
    use bevy::prelude::Event;

    #[derive(Event, Clone, Debug)]
    pub struct PlayerSpawned(pub Entity);

    #[derive(Event, Clone, Debug)]
    pub struct ScoreChanged {
        pub player: Entity,
        pub score: i32,
    }

    #[derive(Event, Clone, Debug)]
    pub struct GameOver;
}

Usage with Bevy Observers

Basic Example

use bevy::prelude::*;
use bevy_enum_event::EnumEvent;

#[derive(EnumEvent, Clone, Copy)]
enum GameState {
    MainMenu,
    Playing,
    Paused,
}

fn setup(app: &mut App) {
    app.observe(on_paused);
}

fn on_paused(trigger: Trigger<game_state::Paused>) {
    println!("Game paused!");
}

With Event Data

use bevy::prelude::*;
use bevy_enum_event::EnumEvent;

#[derive(EnumEvent, Clone)]
enum EntityEvent {
    Spawned(Entity),
    Damaged { entity: Entity, amount: f32 },
    Destroyed(Entity),
}

fn on_entity_damaged(trigger: Trigger<entity_event::Damaged>) {
    let event = trigger.event();
    println!("Entity {:?} took {} damage", event.entity, event.amount);
}

fn on_entity_spawned(trigger: Trigger<entity_event::Spawned>) {
    // With the deref feature (enabled by default), you can access the Entity directly
    let entity: Entity = *trigger.event();
    println!("Entity spawned: {:?}", entity);
}

Feature: deref (enabled by default)

The deref feature automatically derives Bevy's Deref and DerefMut traits for enum variants with a single field (either tuple or named), providing ergonomic access to the inner value. For multi-field variants, you can opt into the same ergonomic access by adding #[enum_event(deref)] to the field you want to expose (the generated struct receives Bevy's #[deref] attribute). If a multi-field variant is not annotated with #[enum_event(deref)], no deref functionality is generated and fields must be accessed directly by name.

Example

use bevy::prelude::*;
use bevy_enum_event::EnumEvent;

#[derive(EnumEvent, Clone)]
enum EntityEvent {
    Spawned(Entity),
    Destroyed(Entity),
    HealthChanged { value: f32 },
    Scored { #[enum_event(deref)] player: Entity, points: u32 },
    TeamScore { team: u32, points: u32 },  // No deref annotation, no derive will happen
}

fn on_spawned(trigger: Trigger<entity_event::Spawned>) {
    // With deref feature, single-field variants can access the Entity directly
    let entity: Entity = *trigger.event();
    println!("Entity spawned: {:?}", entity);
}

fn on_health_changed(trigger: Trigger<entity_event::HealthChanged>) {
    // Deref also works for named single-field variants
    let health: f32 = *trigger.event();
    println!("Health changed to: {}", health);
}

fn on_scored(trigger: Trigger<entity_event::Scored>) {
    // Multi-field variants work when you mark one field with #[enum_event(deref)]
    let player: Entity = *trigger.event();
    println!("Player {player:?} scored!");
}

fn on_team_score(trigger: Trigger<entity_event::TeamScore>) {
    // Multi-field without deref annotation - must access fields directly
    let event = trigger.event();
    println!("Team {} scored {} points", event.team, event.points);
}

Disabling the deref Feature

If you prefer not to have Deref and DerefMut automatically implemented, you can disable the default features:

[dependencies]

bevy_enum_event = { version = "0.1", default-features = false }

When disabled, you'll need to access fields directly:

fn on_spawned(trigger: Trigger<entity_event::Spawned>) {
    let entity: Entity = trigger.event().0;  // Access via .0
    println!("Entity spawned: {:?}", entity);
}

Snake Case Conversion

The macro intelligently converts enum names to snake_case module names:

  • LifeFSMlife_fsm
  • PlayerStateplayer_state
  • HTTPServerhttp_server
  • MyHTTPSConnectionmy_https_connection

Generics & Lifetimes

All derives mirror the generic parameters, lifetimes, and where clauses from your enum onto the generated event structs. This makes it straightforward to use EnumEvent with enums such as:

#[derive(EnumEvent, Clone)]
enum GenericEvent<'a, T>
where
    T: Clone + 'a,
{
    Borrowed(&'a T),
    Owned(T),
    Done,
}

The generated module exposes generic_event::Borrowed<'a, T>, generic_event::Owned<'a, T>, and generic_event::Done<'a, T> types with identical bounds.

Unit event structs expose ergonomic constructors so you never have to juggle hidden PhantomData markers by hand. Every unit variant implements Default, and when a phantom marker is required the derive also emits a new() helper that seeds it for you. Tuple and named variants that require phantom markers likewise receive new(...) helpers that accept only the original fields.

Use Cases

  • State machines (see bevy_fsm)
  • Game state transitions
  • Entity lifecycle events
  • Animation states
  • Input modes
  • Any enum-based event system
  • Network message events
  • Input/Output events with associated data

AI Disclaimer

  • Refactoring and documentation supported by Claude Code
  • Minor editing supported by ChatGPT Codex
  • The process and final releases are thoroughly supervised and checked by the author

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.