/**
A require.s2 module implementing a basic publish-subscriber
manager.
Example usage:
http://fossil.wanderinghorse.net/repos/cwal/index.cgi/finfo?name=s2/require.d/pubsub.test.s2
Returns a class, each instance of which manages its own list
of publishers and subscribers.
*/
return {
__typename: 'PubSub',
prototype: undefined,
/**
Constructor for use with the 'new' keyword.
var pubber = new thisObj();
assert pubber inherits thisObj; // this will hold
Each instance maintains its own, independent list of
subscriptions.
*/
__new: proc(){
this.reset();
},
/**
Subscribes a callback to events published for a given key.
key may be of any value type. func must be-a Function.
Returns a unique-per-subscription value (of an unspecified
type) which can be passed to unsub() to opt out of a
subscription. For a permanent subscription, simply ignore the
result value.
*/
sub:proc callee(key, func){
affirm typeinfo(iscallable func) /* is Function-like */;
const m = (this.$map[key] ||| (this.$map[key]={prototype:null})),
i = enum{k:key}.k;
m[i] = func;
return i;
},
/**
Expects id to be a value returned by this.sub() and
unsubscribes a subscriber registered with that id.
Returns this object.
*/
unsub: proc(id){
affirm typeinfo(isunique id);
(const c = this.$map[id.value]) && unset c[id];
return this;
},
/**
Publishes an event to all subscribers (if any) of the key
(event type) given as the first argument.
Important notes:
a) Subscribers are notified in an UNSPECIFIED and (very)
POSSIBLY CHANGING order.
b) Any arguments given after the event key are passed to each
subscriber callback function, in the order they are passed in
here. e.g. if this function is passed ('foo', 'bar', 1) then
each subscriber will be called with ('bar', 1). Pedantic
side-note: each callback gets its own copy of the arguments
array, to avoid unintended side-effects if a callback modifies
its argv.
Returns this object (for lack of a better option).
It propagates any exceptions thrown by a subscriber, and any
pending subscribers won't get called.
Pedantic side-node: each subscriber gets its own copy of the
arguments array, so it's safe to change it or keep a reference
to it in the subscribers without affecting others.
*/
pub:proc(/*key, event args...*/){
return this.pubWithThis(argv.shift(), undefined, @argv);
},
/**
A special case of pub() useful in certain code constellations.
For each listener of event type e, its callback is called using
t as the callback's "this" and passing on all arguments after
the second. If t is undefined then each callback is its own
'this' (as is conventional for s2).
Returns this object.
See pub() for more details.
*/
pubWithThis: proc(e,t/*...*/){
const m = this.$map[e] ||| return this;
affirm typeinfo(isobject m);
argv.shift(2);
foreach(m=>k,f) f.apply(t?:f, argv.slice());
return this;
},
/**
Removes all subscriptions for the given key or (if no arguments
are passed) all subscriptions for all keys.
Returns this object (for lack of a better option).
*/
reset:proc(/*key*/){
argv.# ? unset this.$map[argv.0] : this.$map = {prototype:null};
return this;
}
};