rs_events

Crates.iors_events
lib.rsrs_events
version0.1.0
created_at2025-09-24 04:32:53.994967+00
updated_at2025-09-24 04:32:53.994967+00
descriptionA flexible and ergonomic event emission crate for Rust. Supports both std/threaded and no_std/alloc environments, with tagging, listener lifetimes, async/sync emission, and robust error handling.
homepagehttps://github.com/GreenJ84/Rust_events_crate
repositoryhttps://github.com/GreenJ84/Rust_events_crate
max_upload_size
id1852495
size179,519
Jesse L. Greenough (GreenJ84)

documentation

https://docs.rs/rs_events

README

rs_events

Crates.io Docs.rs License Build Status

rust_events is a highly flexible, ergonomic, and portable event emitter crate for Rust.

It supports both high-performance threaded applications and minimal no_std/alloc environments, making it suitable for everything from servers to embedded systems.


Quick Example

use rs_events::{EventEmitter, EventPayload};
use std::sync::Arc;

fn main() {
    let mut emitter = EventEmitter::<String>::default();
    emitter.add("event", None, Arc::new(|payload| {
        println!("Received: {}", payload.as_ref());
    })).unwrap();

    emitter.emit("event", Arc::new("Hello World".to_string())).unwrap();
}

Features

  • Dual Environment Support:
    • threaded (default): Uses std, tokio, and dashmap for high concurrency and async support.
    • no_std/alloc: Minimal, dependency-free build for embedded and constrained environments.
  • Listener Types:
    • Unlimited: Listeners persist until explicitly removed.
    • Limited: Listeners auto-remove after a set number of calls.
    • Once: Listeners auto-remove after a single call.
  • Tagging & Lifetimes:
    • Tag listeners for easy identification and management.
    • Provide lifetimes to manage the number of times a listener gets called.
    • Query and remove listeners.
  • Async & Sync Emission:
    • Emit events synchronously or asynchronously (blocking or parallel).
    • Async emission uses tokio for efficient scheduling.
  • Robust Error Handling:
    • Comprehensive error types for missing events, listener overload, and more.
  • Feature-Gated Dependencies:
    • Only include heavy dependencies when needed, keeping builds minimal for embedded use.

Design Rationale

  • Ergonomics:
    • Simple, type-safe API for adding, removing, and emitting events.
    • Arc-based payloads for cheap cloning and thread safety.
  • Performance:
    • Uses dashmap for lock-free, highly concurrent event storage in threaded mode (enabled by the threaded feature). This allows multiple threads to add, remove, and emit events without blocking, making it ideal for servers and async applications.
    • In no_std/alloc mode, falls back to BTreeMap for event storage. BTreeMap is chosen for its minimal dependency footprint and efficient ordered storage, suitable for embedded and constrained environments where concurrency is not available.
    • This dual approach ensures optimal performance and minimal resource usage for both desktop/server and embedded/portable targets.
    • Minimal allocations and fast event dispatch in both modes.
  • Portability:
    • Compile with --no-default-features for no_std/alloc.
    • All core logic is feature-gated for easy adaptation.

Getting Started

Add to your Cargo.toml:

[dependencies]
rust_events = "1.0.0"

Threaded (default)

Build with:

cargo build

Example:

use rust_events::{EventEmitter, EventPayload};
use std::sync::Arc;

fn main() {
    let mut emitter = EventEmitter::<String>::default();
    emitter.add("event", None, Arc::new(|payload| {
        println!("Received: {}", payload.as_ref());
    })).unwrap();
    emitter.emit("event", Arc::new("Hello World".to_string())).unwrap();
}

no_std/alloc

Build with:

cargo build --no-default-features

Use alloc::sync::Arc and alloc::string::String in your code. See crate docs for details.

Example:

extern crate alloc;
use alloc::sync::Arc;
use alloc::string::String;
use rust_events::{EventEmitter, EventPayload};

let mut emitter = EventEmitter::<String>::default();
emitter.add("event", None, Arc::new(|payload| {
  // Handle event
})).unwrap();
emitter.emit("event", Arc::new(String::from("Hello no_std!"))).unwrap();

Usage

Adding Listeners with Tags and Lifetimes

let mut emitter = EventEmitter::<u32>::default();
let listener = emitter.add_limited("count", Some("tag1".to_string()), Arc::new(|payload| {
    println!("Count: {}", payload.as_ref());
}), 5).unwrap();
assert_eq!(listener.tag(), Some(&"tag1".to_string()));
assert_eq!(listener.lifetime(), Some(5));

Async Emission (Blocking and Parallel - Threaded only)

#[tokio::main]
async fn main() {
    let mut emitter = EventEmitter::<String>::default();
    emitter.add("event", None, Arc::new(|payload| {
        println!("Received: {}", payload.as_ref());
    })).unwrap();
    // Blocking mode
    emitter.emit_async("event", Arc::new("Hello Async".to_string()), false).await.unwrap();
    // Parallel mode
    emitter.emit_async("event", Arc::new("Hello Async".to_string()), true).await.unwrap();
}

Removing Listeners

let mut emitter = EventEmitter::<String>::default();
let listener = emitter.add_once("event", Some("tag1".to_string()), Arc::new(|_| {})).unwrap();
emitter.remove_listener("event", &listener).unwrap();

Final Emission and Listener Drop-off

let mut emitter = EventEmitter::<String>::default();
emitter.add("event", None, Arc::new(|_| {})).unwrap();
let falloff = emitter.emit_final("event", Arc::new("Final".to_string())).unwrap();
assert_eq!(falloff.len(), 1); // Listener removed after final emit

Feature Flags

  • threaded (default): Enables std/threaded support and dependencies (tokio, dashmap, futures).
  • Build with --no-default-features for no_std/alloc.

Documentation

License

MIT OR Apache-2.0

Contributing

We welcome contributions of all kinds—bug reports, feature requests, documentation improvements, and code enhancements. Please:

  • Open issues for bugs, questions, or feature ideas.
  • Submit pull requests for code or documentation improvements.
  • Follow the coding style and guidelines outlined in CONTRIBUTING.md.

See CONTRIBUTING.md for full details on how to get started, code standards, and the review process.

Author

Jesse Greenough

Commit count: 50

cargo fmt