tomo/event/event.go

86 lines
2.0 KiB
Go

// Package event provides a system for broadcasting events to multiple event
// handlers.
package event
// A cookie is returned when you add an event handler so you can remove it
// later if you so choose.
type Cookie interface {
// Close removes the event handler this cookie is for.
Close ()
}
// Broadcaster manages event listeners.
type Broadcaster[L any] struct {
lastID int
listeners map[int] L
}
// Connect adds a new listener to the broadcaster and returns a corresponding
// cookie.
func (broadcaster *Broadcaster[L]) Connect (listener L) Cookie {
broadcaster.ensure()
cookie := broadcaster.newCookie()
broadcaster.listeners[cookie.id] = listener
return cookie
}
// Listeners returns a map of all connected listeners.
func (broadcaster *Broadcaster[L]) Listeners () map[int] L {
broadcaster.ensure()
return broadcaster.listeners
}
func (broadcaster *Broadcaster[L]) newCookie () cookie[L] {
broadcaster.lastID ++
return cookie[L] {
id: broadcaster.lastID,
broadcaster: broadcaster,
}
}
func (broadcaster *Broadcaster[L]) ensure () {
if broadcaster.listeners == nil {
broadcaster.listeners = make(map[int] L)
}
}
// NoCookie is a cookie that does nothing when closed.
type NoCookie struct { }
func (NoCookie) Close () { }
type cookie[L any] struct {
id int
broadcaster *Broadcaster[L]
}
func (cookie cookie[L]) Close () {
delete(cookie.broadcaster.listeners, cookie.id)
}
// FuncBroadcaster is a broadcaster that manages functions with no arguments.
type FuncBroadcaster struct {
Broadcaster[func ()]
}
// Broadcast calls all connected listener funcs.
func (broadcaster *FuncBroadcaster) Broadcast () {
for _, listener := range broadcaster.Listeners() {
listener()
}
}
type multiCookie []Cookie
// MultiCookie creates a single cookie that, when closed, closes a list of other
// cookies.
func MultiCookie (cookies ...Cookie) Cookie {
return multiCookie(cookies)
}
func (cookies multiCookie) Close () {
for _, cookie := range cookies {
cookie.Close()
}
}