nupp.events
Addressed, synchronous events whose payloads are ordinary declarations.
An event is a record or a fixed-layout struct marked @derive(events.Event). Emitting one by type constructs it into storage the source already owns, and only when something at that address is observing; delivering an instance the caller built allocates nothing. Observers receive the event as a call-scoped borrow they may write to but not keep.
local events = nupp.events
(events.Event)
local record Damage
amount: number
source: integer
kind: string = "physical"
end
local bus: events.MessageBus<integer> = events.newMessageBus()
bus:observe(7, Damage, |event| -> print(event.amount, event.kind), "log")
bus:emit(7, Damage, amount = 10, source = 3)Here bus is the event source: it owns the observer registry and reusable event storage. 7 is the address within that source, so observers registered at another entity id do not receive this delivery. The MessageBus methods forward to the module functions below; the equivalent direct call is events.observe(bus, 7, Damage, callback, "log").
Observer state belongs to a source: MessageBus<A> is one, and any record with an observers field implements nupp.events.Source and dispatches through the same functions. Record events draw from a nupp.mem.pool and struct events from a nupp.mem.arena, each created the first time an event type is emitted through a source; setAllocator installs one the caller owns instead. NEP 29 records the design.
Module contents
Constructors
| Constructor | Description |
|---|---|
newMessageBus | A bus with no observers. |
newObservers | Empty observer state for a new source. |
Types
| Type | Kind | Description |
|---|---|---|
Allocator | interface | Storage an event type is constructed into and returned to. |
Emittable | interface | What a declaration becomes by deriving events.Event. |
MessageBus | record | A source that is nothing but its observers. |
Observer | type | An observer of one event type. |
Observers | record | Observer registrations for one source, keyed by address and event identity. |
Source | interface | Something that owns observer state. |
Functions
| Function | Kind | Description |
|---|---|---|
clearAddress | function | Removes every registration at one address. |
deliver | function | Delivers an event instance the caller already holds. |
emit | function | Constructs an event into the source's storage and delivers it. |
Event | comptime function | Marks a record or a fixed-layout struct as an event. |
hasObservers | function | Whether anything observes one event type at one address. |
id | function | The identity an event type has in this runtime. |
name | function | The name an event type registered under. |
observe | function | Registers an observer of one event type at one address. |
observeOnce | function | Registers an observer that is consumed before its first delivery. |
reset | function | Removes every registration at every address. |
setAllocator | function | Installs the storage one event type is constructed into at this source. |
stopObserving | function | Removes registrations at one address and event. |
Constructors#
events.newMessageBusconstructor#
function events.newMessageBus<A>(): events.MessageBus<A>A bus with no observers.
The address type is whatever the binding asks for: local bus: events.MessageBus<integer> = events.newMessageBus().
Type parameters
| Name | Description |
|---|---|
A |
Returns
| Type | Description |
|---|---|
events.MessageBus<A> | the bus |
events.newObserversconstructor#
function events.newObservers<A>(): events.Observers<A>Empty observer state for a new source.
Type parameters
| Name | Description |
|---|---|
A |
Returns
| Type | Description |
|---|---|
events.Observers<A> | the state, with nothing registered |
Types#
Allocatorinterface#
interface events.Allocator<E>
acquire: function(exclusive self: Allocator<E>): E
release: function(exclusive self: Allocator<E>, value: E): nil
endStorage an event type is constructed into and returned to.
acquire hands out reusable storage of the event's own representation, which the emitting source initializes; release ends that lease when delivery is over. nupp.mem.pool and nupp.mem.arena implement it.
Type parameters
| Name | Description |
|---|---|
E |
Methods
Emittableinterface#
interface events.Emittable
endWhat a declaration becomes by deriving events.Event.
The bound an event type parameter carries, so a source refuses a record that never derived the event contract before anything runs.
MessageBusrecord#
record events.MessageBus<A> is events.Source<A>
observers: events.Observers<A>
observe: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callback: events.Observer<E>,
id: string?
): nil
observeOnce: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callback: events.Observer<E>,
id: string?
): nil
stopObserving: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callbackOrId: events.Observer<E> | string
): boolean
hasObservers: function<E is events.Emittable>(self: MessageBus<A>, address: A, event: Type<E>): boolean
emit: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
...: unpackof Construction(E)
): nil
deliver: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
instance: E
): nil
clearAddress: function(exclusive self: MessageBus<A>, address: A): nil
reset: function(exclusive self: MessageBus<A>): nil
setAllocator: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
event: Type<E>,
allocator: events.Allocator<E>
): nil
endA source that is nothing but its observers.
Every method forwards to the function of the same name, passing the bus as the source that owns observer state.
Type parameters
| Name | Description |
|---|---|
A |
Methods
observe#
observe: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callback: events.Observer<E>,
id: string?
): nilRegisters an observer; see nupp.events.observe.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A | |
event | Type<E> | |
callback | events.Observer<E> | |
id | string? |
Returns
| Type | Description |
|---|---|
nil |
observeOnce#
observeOnce: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callback: events.Observer<E>,
id: string?
): nilRegisters an observer consumed on first delivery; see nupp.events.observeOnce.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A | |
event | Type<E> | |
callback | events.Observer<E> | |
id | string? |
Returns
| Type | Description |
|---|---|
nil |
stopObserving#
stopObserving: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
callbackOrId: events.Observer<E> | string
): booleanRemoves registrations; see nupp.events.stopObserving.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A | |
event | Type<E> | |
callbackOrId | events.Observer<E> | string |
Returns
| Type | Description |
|---|---|
boolean |
hasObservers#
hasObservers: function<E is events.Emittable>(self: MessageBus<A>, address: A, event: Type<E>): booleanWhether anything observes an event here; see nupp.events.hasObservers.
Arguments
| Name | Type | Description |
|---|---|---|
self | MessageBus<A> | |
address | A | |
event | Type<E> |
Returns
| Type | Description |
|---|---|
boolean |
emit#
emit: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
...: unpackof Construction(E)
): nilConstructs and delivers an event; see nupp.events.emit.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A | |
event | Type<E> | |
... | unpackof Construction(E) |
Returns
| Type | Description |
|---|---|
nil |
deliver#
deliver: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
address: A,
event: Type<E>,
instance: E
): nilDelivers an instance; see nupp.events.deliver.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A | |
event | Type<E> | |
instance | E |
Returns
| Type | Description |
|---|---|
nil |
clearAddress#
clearAddress: function(exclusive self: MessageBus<A>, address: A): nilRemoves every registration at an address; see nupp.events.clearAddress.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
address | A |
Returns
| Type | Description |
|---|---|
nil |
reset#
reset: function(exclusive self: MessageBus<A>): nilRemoves every registration; see nupp.events.reset.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> |
Returns
| Type | Description |
|---|---|
nil |
setAllocator#
setAllocator: function<E is events.Emittable>(
exclusive self: MessageBus<A>,
event: Type<E>,
allocator: events.Allocator<E>
): nilInstalls storage for an event type; see nupp.events.setAllocator.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive self | MessageBus<A> | |
event | Type<E> | |
allocator | events.Allocator<E> |
Returns
| Type | Description |
|---|---|
nil |
Fields
Observertype#
type events.Observer<E> = function(borrows event: E): nilAn observer of one event type.
The event is borrowed for the call: it may be read and written, and cannot be stored or returned. State beyond the event is explicit: capture it in the observer or carry it as an event field.
Type parameters
| Name | Description |
|---|---|
E |
Observersrecord#
Observer registrations for one source, keyed by address and event identity.
A source holds one of these in its observers field. Nothing exists for an address until something observes there, so a world of millions of entities pays for the observers it has and not for the entities it could have.
Type parameters
| Name | Description |
|---|---|
A |
Fields
Sourceinterface#
Something that owns observer state.
A bus or a world implements this by holding an observers field; the dispatch functions take the source exclusively and reach its state through that field. The source is not implicitly passed to observers.
Type parameters
| Name | Description |
|---|---|
A |
Fields
Functions#
events.clearAddressfunction#
function events.clearAddress<A, S is events.Source<A>>(exclusive source: S, borrows address: A): nilRemoves every registration at one address.
A delivery in flight at that address finishes the list it already holds; the next emission there finds nothing. Registrations at other addresses are untouched, which is how a world clears an entity without losing what observes the world itself.
Type parameters
| Name | Description |
|---|---|
A | |
S |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world |
borrows address | A | the address to clear |
Returns
| Type | Description |
|---|---|
nil |
events.deliverfunction#
function events.deliver<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, borrows address: A, event: Type<E>, instance: E): nilDelivers an event instance the caller already holds.
The instance is neither acquired nor released: what the caller built stays the caller's, and is handed to each observer as the borrow its contract names. Everything else is as emit.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world |
borrows address | A | where to deliver |
event | Type<E> | the event declaration |
instance | E | the instance to deliver |
Returns
| Type | Description |
|---|---|
nil |
Raises
what an observer raised
events.emitfunction#
function events.emit<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, borrows address: A, event: Type<E>, ...: unpackof Construction(E)): nilConstructs an event into the source's storage and delivers it.
Nothing is acquired, initialized, or run when no observer is registered at the address for the event: the argument expressions are evaluated as they are for any call, and that is all. Otherwise storage is leased from the event's allocator, the declaration's initializer fills it from the arguments, applying a field default where an argument is nil, every observer registered when the delivery began runs in order, and the lease is released whether the delivery returned, raised, or was cancelled while an observer was suspended.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world |
borrows address | A | where to deliver |
event | Type<E> | the event declaration |
... | unpackof Construction(E) | the event's constructor arguments, positional or named |
Returns
| Type | Description |
|---|---|
nil |
Raises
what an observer or the initializer raised, after the lease is released
events.Eventcomptime function#
Marks a record or a fixed-layout struct as an event.
The derive records the event's name and representation, and asks the compiler for the declaration's initializer: its constructor body, or its field list, run against storage a source already holds. A declaration with several constructors, one whose constructor keeps self or moves an owner into it, an affine field, or a generic owner is refused, since none of those can run against reused storage.
Arguments
| Name | Type | Description |
|---|---|---|
info | nupp.derive.Info | the declaration being derived |
Returns
| Type | Description |
|---|---|
nupp.derive.Result<events.Emittable> | the recipe claiming |
events.hasObserversfunction#
function events.hasObservers<A, S is events.Source<A>, E is events.Emittable>(borrows source: S, borrows address: A, event: Type<E>): booleanWhether anything observes one event type at one address.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
borrows source | S | the bus or world |
borrows address | A | the address to ask about |
event | Type<E> | the event declaration |
Returns
| Type | Description |
|---|---|
boolean | whether a delivery there would reach an observer |
events.idfunction#
The identity an event type has in this runtime.
Assigned once, the first time a source, id, or name asks, from a counter local to this Lua state. It is stable for the life of the state and is never a persistent or wire identity.
Type parameters
| Name | Description |
|---|---|
E |
Arguments
| Name | Type | Description |
|---|---|---|
event | Type<E> | the event declaration |
Returns
| Type | Description |
|---|---|
integer | its identity |
Raises
when the type did not derive
events.Event
events.namefunction#
The name an event type registered under.
Type parameters
| Name | Description |
|---|---|
E |
Arguments
| Name | Type | Description |
|---|---|---|
event | Type<E> | the event declaration |
Returns
| Type | Description |
|---|---|
string | the declared or |
Raises
when the type did not derive
events.Event
events.observefunction#
function events.observe<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, borrows address: A, event: Type<E>, callback: events.Observer<E>, id: string?): nilRegisters an observer of one event type at one address.
Observers run in registration order. A name lets stopObserving remove this registration by name; a name already registered at the same address and event is an error, since the second could never be removed alone.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world that owns the observer registry and event storage |
borrows address | A | where the event is delivered |
event | Type<E> | the event declaration |
callback | events.Observer<E> | what runs when one is delivered |
id | string? | an optional name for removal |
Returns
| Type | Description |
|---|---|
nil |
Raises
when the type did not derive
events.Event, or the name is taken
events.observeOncefunction#
function events.observeOnce<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, borrows address: A, event: Type<E>, callback: events.Observer<E>, id: string?): nilRegisters an observer that is consumed before its first delivery.
The registration is tombstoned before the callback is invoked, so a nested or interleaved delivery of the same event never reaches it again, whatever the callback goes on to do.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world to observe through |
borrows address | A | where the event is delivered |
event | Type<E> | the event declaration |
callback | events.Observer<E> | what runs, once |
id | string? | an optional name for removal |
Returns
| Type | Description |
|---|---|
nil |
Raises
when the type did not derive
events.Event, or the name is taken
events.resetfunction#
Removes every registration at every address.
Allocators are left alone: an arena the caller installed is still theirs, and the source's own storage is reused by the next emission.
Type parameters
| Name | Description |
|---|---|
A | |
S |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world |
Returns
| Type | Description |
|---|---|
nil |
events.setAllocatorfunction#
function events.setAllocator<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, event: Type<E>, allocator: events.Allocator<E>): nilInstalls the storage one event type is constructed into at this source.
The allocator is the caller's: it must outlive the source's use of it, and the source never resets or closes it. Replacing one while a delivery holds storage from it is refused, since the lease would have nowhere to return.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world |
event | Type<E> | the event declaration |
allocator | events.Allocator<E> | storage of the event's representation |
Returns
| Type | Description |
|---|---|
nil |
Raises
when a delivery of that event is active
events.stopObservingfunction#
function events.stopObserving<A, S is events.Source<A>, E is events.Emittable>(exclusive source: S, borrows address: A, event: Type<E>, callbackOrId: events.Observer<E> | string): booleanRemoves registrations at one address and event.
Given a name, the first registration with that name goes; given a callback, every registration of it goes. A removal during a delivery takes effect at once for anything not yet reached and is compacted out after the outermost delivery leaves. A caller removing by callback keeps the value it registered: a short function is a fresh object each time its expression runs.
Type parameters
| Name | Description |
|---|---|
A | |
S | |
E |
Arguments
| Name | Type | Description |
|---|---|---|
exclusive source | S | the bus or world observed through |
borrows address | A | where the registration was made |
event | Type<E> | the event declaration |
callbackOrId | events.Observer<E> | string | the callback registered, or the name it was given |
Returns
| Type | Description |
|---|---|
boolean | whether anything was removed |