mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-01-08 21:17:51 +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:
parent
fce16ffb87
commit
9809321f6f
|
@ -38,32 +38,48 @@ 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)
|
||||||
|
|
||||||
h.mutex.RLock()
|
all := h.AllCallersForType(t)
|
||||||
defer h.mutex.RUnlock()
|
all(func(caller Caller) bool {
|
||||||
|
caller.Call(v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
typedHandlers := h.events[t].Entries
|
// AllCallersForType returns all callers for the given event type. This is an
|
||||||
anyHandlers := h.events[nil].Entries
|
// 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()
|
||||||
|
defer h.mutex.RUnlock()
|
||||||
|
|
||||||
if len(typedHandlers) == 0 && len(anyHandlers) == 0 {
|
typedHandlers := h.events[t].Entries
|
||||||
return
|
anyHandlers := h.events[nil].Entries
|
||||||
}
|
|
||||||
|
|
||||||
v := reflect.ValueOf(ev)
|
if len(typedHandlers) == 0 && len(anyHandlers) == 0 {
|
||||||
|
return
|
||||||
for _, entry := range typedHandlers {
|
|
||||||
if entry.isInvalid() {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
entry.Call(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, entry := range anyHandlers {
|
for _, entry := range typedHandlers {
|
||||||
if entry.isInvalid() || entry.not(t) {
|
if entry.isInvalid() {
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
if !yield(entry) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range anyHandlers {
|
||||||
|
if entry.isInvalid() || entry.not(t) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !yield(entry) {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry.Call(v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue