1 unstable release

Uses old Rust 2015

0.1.0 Sep 19, 2018

#1975 in Rust patterns

MPL-2.0 license

11KB
153 lines

handler_map

like AnyMap, but with functions instead of values

This crate began with an idle thought: "Crates like AnyMap let you store one value of each type. What would it take to instead store a function that took that type, like a message handler?" What came out was this.

The basic idea is that you start with a message type, and a function that receives it by-value:

struct MyMessage;
fn handle_msg(_: MyMessage) {
    println!("Got your message!");
}

Then, take one of these HandlerMaps, and hand it the handler:

let mut map = HandlerMap::new();
map.insert(handle_msg);

This registers that type in the handler so you can call it later:

map.call(MyMessage);

// console prints "Got your message!"

lib.rs:

Crate which contains a "handler map", a structure that maps message types with "handlers" that can be called with them.

The focal point of this crate is the HandlerMap type, which stores information about functions which receive various types. This can be used to encode event handlers, message handlers, or other situations where you want to dynamically select a function to call based on the data it receives.

To register a handler, pass it to insert:

use handler_map::HandlerMap;

/// Message which prints to the console when received.
struct MyMessage;

fn handle(_: MyMessage) {
    println!("got your message!");
}

let mut map = HandlerMap::new();
map.insert(handle);

This adds the handler to the map so that it can be called later on:




map.call(MyMessage);

The map can also take closures, as long as they implement Fn and don't capture any references to their environment:

use handler_map::HandlerMap;
use std::rc::Rc;
use std::cell::Cell;

/// Message which increments an accumulator when received.
struct MyMessage;

let mut map = HandlerMap::new();
let acc = Rc::new(Cell::new(0));
{
    let acc = acc.clone();
    map.insert(move |_: MyMessage| {
        acc.set(acc.get() + 1);
    });
}

// call the handler a few times to increment the counter
map.call(MyMessage);
map.call(MyMessage);
map.call(MyMessage);

assert_eq!(acc.get(), 3);

call can take a message of any type, even if that type hasn't been registered. It returns a bool representing whether a handler was called. If a handler for that type has been registered in the map, it returns true; otherwise, it returns false. If you want to check that a handler has been registered without calling it, use is_registered or val_is_registered.

If you want to remove an event from the handler, call remove:

use handler_map::HandlerMap;

struct MyMessage;
fn handle_msg(_: MyMessage) {}

let mut map = HandlerMap::new();
map.insert(handle_msg);

assert!(map.is_registered::<MyMessage>());

map.remove::<MyMessage>();

assert!(!map.is_registered::<MyMessage>());

No runtime deps