1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2025-01-09 13:37:02 +00:00

handler: Add AllCallersForType for low-level control

This is needed in more silly main thread applications to prevent mutex
deadlocks from uncontrollable recursions.
This commit is contained in:
diamondburned 2023-12-27 19:19:23 -08:00
parent fce16ffb87
commit 9809321f6f
No known key found for this signature in database
GPG key ID: D78C4471CE776659

View file

@ -38,8 +38,21 @@ func New() *Handler {
// Call calls all handlers with the given event. This is an internal method; use // Call calls all handlers with the given event. This is an internal method; use
// with care. // with care.
func (h *Handler) Call(ev interface{}) { func (h *Handler) Call(ev interface{}) {
v := reflect.ValueOf(ev)
t := reflect.TypeOf(ev) t := reflect.TypeOf(ev)
all := h.AllCallersForType(t)
all(func(caller Caller) bool {
caller.Call(v)
return true
})
}
// AllCallersForType returns all callers for the given event type. This is an
// internal method that is rarely useful for external use and should be used
// with care.
func (h *Handler) AllCallersForType(t reflect.Type) func(yield func(Caller) bool) {
return func(yield func(Caller) bool) {
h.mutex.RLock() h.mutex.RLock()
defer h.mutex.RUnlock() defer h.mutex.RUnlock()
@ -50,20 +63,23 @@ func (h *Handler) Call(ev interface{}) {
return return
} }
v := reflect.ValueOf(ev)
for _, entry := range typedHandlers { for _, entry := range typedHandlers {
if entry.isInvalid() { if entry.isInvalid() {
continue continue
} }
entry.Call(v) if !yield(entry) {
return
}
} }
for _, entry := range anyHandlers { for _, entry := range anyHandlers {
if entry.isInvalid() || entry.not(t) { if entry.isInvalid() || entry.not(t) {
continue continue
} }
entry.Call(v) if !yield(entry) {
return
}
}
} }
} }
@ -239,6 +255,10 @@ func (h *Handler) addHandler(fn interface{}, sync bool) (rm func(), err error) {
}, nil }, nil
} }
// Caller is an interface that can be used to call a handler.
// It directly accepts a reflect.Value, which is the event.
type Caller interface{ Call(ev reflect.Value) }
type handler struct { type handler struct {
event reflect.Type // underlying type; arg0 or chan underlying type event reflect.Type // underlying type; arg0 or chan underlying type
callback reflect.Value callback reflect.Value
@ -248,6 +268,8 @@ type handler struct {
isOnce bool isOnce bool
} }
var _ Caller = (*handler)(nil)
// newHandler reflects either a channel or a function into a handler. A function // newHandler reflects either a channel or a function into a handler. A function
// must only have a single argument being the event and no return, and a channel // must only have a single argument being the event and no return, and a channel
// must have the event type as the underlying type. // must have the event type as the underlying type.