gawk 0.3.2

A simple, flexible observer pattern implementation
Documentation
gawk-0.3.2 has been yanked.

gawk

gawk is a simple but flexible observer library for Rust.

Goals

Simplicity

gawk has a simple API using basic Rust types. The complex types needed to make it work are all abstracted away from the consumer.

Flexibility

  • A gawk Publisher can handle any number of different types of events and handlers.
  • You can create a handler by wrapping a simple closure in gawk's Handler struct, or you can implement the Handle trait manually on your own types. You can even do both for different handlers subscribed to the same Publisher.

Usage

Subscribe a simple closure

use gawk::{Event, Handler, Publisher};

#[derive(Clone, Event)]
struct Warning(String);

#[derive(Clone, Event)]
struct Info(String);

fn main() {
    let mut publisher = Publisher::default();
    let warning_handler = Handler::new(|warning: Warning| println!("Warning: {}", warning.0));
    let warning_id = publisher.subscribe(warning_handler);

    // `publish` returns a Result, the error variant of which contains any errors returned by triggered handlers
    let _ = publisher.publish(Warning(String::from("Looks sus")));

    // This event will not trigger the warning_handler because it's of the wrong concrete type
    let _ = publisher.publish(Info(String::from("All good")));

    publisher.unsubscribe(warning_id);
}

Subscribe a custom type with a mut handler function

use gawk::{Event, Publisher, HandleMut};

#[derive(Clone, Event)]
struct Info(String);

#[derive(Default)]
struct InfoHandler {
    count: usize;
}

impl HandleMut for InfoHandler {
    type EventType = Info;

    fn handle_mut(&mut self, event: Self::EventType) {
        self.count += 1;
        println!("Info: {}", event.0)
        println!("Triggered {} times", self.count);
    }
}

fn main() {
    let mut publisher = Publisher::default();
    let info_handler = InfoHandler::default();
    let info_id = publisher.subscribe_mut(info_handler);

    let _ = publisher.publish(Info(String::from("All good"))); 

    publisher.unsubscribe_mut(info_id);
}

Check out the examples directory for more!

TODO:

  • Publisher supports any number of handlers / events of different types
  • Derive macro for Event trait
  • Optional async feature using Tokio
  • Support handlers that take a mut &self receiver when implementing Handle for custom types to enable more complex use cases, e.g. updating some internal state when events are received

Acknowledgements

Thanks to @klaatu01 for giving me the idea to build this and the coaching I needed to wrangle Rust's type system into allowing events and handlers of multiple different types in a single publisher.