AdamTriggers Module / 2002-10-05 / v0.85.0 / pre-release
-------------------
Adam D. Moss / adam@icculus.org / adam@gimp.org

NOTE
----
This is a pre-release of the AdamTriggers module.  The API and functionality
are not necessarily fixed or rigorously tested at this point, and neither
are the examples or documentation exhaustive.  No home page yet.


WHAT
----
This is a portable, small and fast triggers/listeners library implemented
in C and released under a BSD-style license (essentially meaning that you may
use it freely in commercial, non-commercial, open or closed-source products
and if it breaks then you get to keep all seventeen pieces).  The AdamTriggers
module compiles to around 3K of executable code on x86/gcc, and uses no global
or static data.

Triggers emit events and Listeners pick up these events.  Any number
of Listeners can listen for particular event types they are interested
in from particular Triggers.  When a Trigger fires an event, all
Listeners interested in that event type from that Trigger will be informed
by having their Listener-specific callback function invoked with the event
type, a Listener-specific pointer, and an optional event-specific payload
concerning that event.

The nature of events and their payloads are agreed between the Listener
and the Trigger.  The AdamTriggers module does not know or care about
the meaning of your application-specific event types.  These are identified
at run-time by four-character mnemonics of your choosing, and their payloads
passed as void* pointers.

The routines comprising AdamTriggers are designed for speed and simplicity
while maintaining fair flexibility.  Some limitations have been designed-in
to support these goals while discouraging potentially dangerous usage
patterns.

AdamTriggers, although general-purpose, are geared towards facilitating
event-driven game worlds.  One goal that they are designed towards is that
it should be cheap for the application to trigger events profusely and let
the trigger system care whether anyone is listening.  Read the 'DESIGN
LIMITATIONS' sections below for some current caveats, however.

Triggers and Listeners are identified by pointers to their respective
structures.  It is safe, however, to use the deletion API calls on
Triggers with outstanding Listeners (and Listeners with outstanding
Triggers) without leaving dangling pointers, since they know how to
inform each other about deletions and subsequently clean up.

Listeners may be marked as 'auto-delete' with the listenerAllowAutoDelete()
API call.  An auto-delete Listener is a Listener that is allowed to
automatically free itself when all of the Triggers it is watching have been
deleted.  This is simply for convenience so that the application doesn't have
to keep track of such Listeners whose lifetimes are closely tied to the
Triggers they are watching.


INCLUDING ADAMTRIGGERS IN YOUR CODE
-----------------------------------

To use the AdamTriggers module in your code, simply #include "triggers.h"
in the source files that need access to the AdamTriggers API and link
your final program with the object file that you get from compiling
triggers.c.

For example, to compile triggers.c into triggers.o under most unixoids:

  cc -c triggers.c

...and to link the resulting triggers.o with your own application objects
to create an executable program:

  cc triggers.o mymodule1.o mymodule2.o -o myapplication

For further details on the API, see triggers.h and example.c


GOTCHAS AND DESIGN LIMITATIONS
------------------------------
* Events are delivered to interested Listeners synchronously and in
  essentially random order.
* A maximum of 256 distinct event types may be concurrently listened for on
  a single Trigger.  A #define in triggers.h can lower this figure to save
  space.  This figure cannot be raised further without some (minor) work.
* The event payload's data belongs to the code triggering the event and hence
  the given pointer is not expected to be valid once the event has finished
  being acted upon.  Combined with synchronous delivery this ensures that it
  is safe to pass pointers to data on the stack when triggering events, for
  speed and convenience.
* An auto-delete Listener should generally never be explicitly deleted
  after being marked as auto-delete.  For an explanation of why, see
  triggers.c:listenerDelete()
* A Listener without a callback function defined is possible but useless.
* An auto-delete Listener will never get automatically deleted if it never
  asks to watch a Trigger.


GOTCHAS AND LIMITATIONS THAT *MIGHT* BE LIFTED IN THE FUTURE
------------------------------------------------------------
* API is not necessarily fixed at this point.
* Listener destructor event callbacks are untested.
* We assume that realloc() is pretty cheap, as it is on Linux/glibc2.
* It is not safe to use AdamTriggers from more than one thread.
* It is not safe to implicitly or explicitly modify a Trigger from an
  event triggered from that Trigger.
* A callback isn't explicitly told which Listener it was called from.  You
  can put this information in the Listener-specific data hook
  (listenerSetData()) if it is required, which is passed to the callback
  as the void* listener_data parameter.
* A callback isn't explicitly told which Trigger caused it to be called.  The
  event-firing code can put this information in the event payload if it is
  required.
* Any Listener's callback should expect to get a listener destructor event
  (currently "/LDe", changable from triggers.h) in addition to the events it
  is explicitly expecting to receive.


FUTURE
------
* Reduce Trigger structure's footprint (~2K now).  I have plans for this.
* Triggering events for which there are no listeners is much more
  expensive than triggering events for which there are listeners, because
  of the specific hash implementation.  I have plans for this.
* Allow application to be told when the Trigger's event table is full.
* I am working on an interface for triggering and receiving events across
  a C<->lua boundary.  This may or may not form part of AdamTriggers.
* Improve docs and example.c
* I do not expect to expand the basic functionality of AdamTriggers.
* AdamTriggers needs a less moronic name.


If you use AdamTriggers in your project then I'd be interested in knowing!

Cheers,
--Adam
