From 88335b6f5470e2b195363c631c40d03637379ef6 Mon Sep 17 00:00:00 2001 From: Chris Rhodes Date: Sun, 14 Feb 2016 19:01:45 -0800 Subject: [PATCH] Small performance improvement. Added tests. --- discord.go | 12 +++++++----- discord_test.go | 36 ++++++++++++++++++++++++++++++++++++ structs.go | 8 +++++++- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/discord.go b/discord.go index dd436c8..cf276e7 100644 --- a/discord.go +++ b/discord.go @@ -151,10 +151,10 @@ func (s *Session) AddHandler(handler interface{}) { handlers := s.Handlers[eventType] if handlers == nil { - handlers = []interface{}{} + handlers = []reflect.Value{} } - handlers = append(handlers, handler) + handlers = append(handlers, reflect.ValueOf(handler)) s.Handlers[eventType] = handlers } @@ -162,15 +162,17 @@ func (s *Session) handle(event interface{}) { s.RLock() defer s.RUnlock() + handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)} + if handlers, ok := s.Handlers[reflect.TypeOf(event)]; ok { for _, handler := range handlers { - reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}) + handler.Call(handlerParameters) } } if handlers, ok := s.Handlers[nil]; ok { for _, handler := range handlers { - reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}) + handler.Call(handlerParameters) } } } @@ -178,7 +180,7 @@ func (s *Session) handle(event interface{}) { // initialize adds all internal handlers and state tracking handlers. func (s *Session) initialize() { s.Lock() - s.Handlers = map[interface{}][]interface{}{} + s.Handlers = map[interface{}][]reflect.Value{} s.Unlock() s.AddHandler(s.onEvent) diff --git a/discord_test.go b/discord_test.go index 687f820..7442651 100644 --- a/discord_test.go +++ b/discord_test.go @@ -224,3 +224,39 @@ func TestOpenClose(t *testing.T) { t.Fatalf("TestClose, d.Close failed: %+v", err) } } + +func TestHandlers(t *testing.T) { + testHandlerCalled := false + testHandler := func(s *Session, t *testing.T) { + testHandlerCalled = true + } + + interfaceHandlerCalled := false + interfaceHandler := func(s *Session, i interface{}) { + interfaceHandlerCalled = true + } + + bogusHandlerCalled := false + bogusHandler := func(s *Session, se *Session) { + bogusHandlerCalled = true + } + + d := Session{} + d.AddHandler(testHandler) + d.AddHandler(interfaceHandler) + d.AddHandler(bogusHandler) + + d.handle(t) + + if !testHandlerCalled { + t.Fatalf("testHandler was not called.") + } + + if !interfaceHandlerCalled { + t.Fatalf("interfaceHandler was not called.") + } + + if bogusHandlerCalled { + t.Fatalf("bogusHandler was called.") + } +} diff --git a/structs.go b/structs.go index 1bb8279..8185902 100644 --- a/structs.go +++ b/structs.go @@ -13,6 +13,7 @@ package discordgo import ( "encoding/json" + "reflect" "sync" "time" @@ -29,7 +30,12 @@ type Session struct { Token string // Authentication token for this session Debug bool // Debug for printing JSON request/responses - Handlers map[interface{}][]interface{} + // This is a mapping of event structs to a reflected value + // for event handlers. + // We store the reflected value instead of the function + // reference as it is more performant, instead of re-reflecting + // the function each event. + Handlers map[interface{}][]reflect.Value // Exposed but should not be modified by User. SessionID string // from websocket READY packet