Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit edd5436

Browse files
author
ns2020
committed
init golang tiny lib, with htevent
0 parents commit edd5436

File tree

6 files changed

+334
-0
lines changed

6 files changed

+334
-0
lines changed

‎README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# HT tiny golang tools lib
2+
3+
build the smallest tools lib for golang,
4+
5+
to be continue...
6+
7+
## htevent
8+
9+
tiny event dispatcher, for binding msg and msn handler.
10+
11+
### usage
12+
See htevent/README.md
13+
14+
15+
16+
#LICENSE
17+
[MIT](https://opensource.org/licenses/MIT "MIT")
18+
19+
20+
Copyright (c) 2008 HOTTARO. All rights reserved.
21+
22+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
23+
24+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
25+
26+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27+

‎htevent/.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: go
2+
3+
go:
4+
- 1.3
5+
- 1.4
6+
- tip
7+
8+
before_install:
9+
- go get github.com/axw/gocov/gocov
10+
- go get github.com/mattn/goveralls
11+
- go get golang.org/x/tools/cmd/cover
12+
13+
script:
14+
- "go version | grep '1.3' && go test -v --race || $HOME/gopath/bin/goveralls -repotoken $COVERALLS_TOKEN"

‎htevent/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# tiny event dispatcher
2+
3+
# example
4+
5+
```go
6+
package main
7+
8+
import (
9+
"fmt"
10+
"./event"
11+
)
12+
13+
func main() {
14+
15+
dispatcher := htevent.NewHTDispatcher()
16+
dispatcher.On("msg0", func(i int){
17+
fmt.Printf("msg0 dispatch ok : %d\n", i)
18+
})
19+
dispatcher.On("msg1", func(s string){
20+
fmt.Printf("msg1 dispatch ok : %s\n", s)
21+
})
22+
23+
dispatcher.Handler("msg0", 0)
24+
err := dispatcher.Handler("msg2", 0) // error
25+
fmt.Println(err)
26+
dispatcher.Handler("msg1", "str")
27+
err = dispatcher.Handler("msg1", 0) // error
28+
fmt.Println(err)
29+
}
30+
31+
```
32+
33+
# result
34+
35+
```sh
36+
msg0 dispatch ok : 0
37+
msg2 event has not been defined yet.
38+
msg1 dispatch ok : str
39+
Argument Error. Args[0] expected string, but got int
40+
```
41+

‎htevent/htdispatcher.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package htevent
2+
3+
import "sync"
4+
5+
// HTDispatcher is an event htDispatcher.
6+
type HTDispatcher interface {
7+
Handler(name string, args ...interface{}) error
8+
// f is a function
9+
On(name string, f interface{}) error
10+
Off(name string, f interface{}) error
11+
// Destroy a event
12+
Destroy(name string) error
13+
}
14+
15+
type htDispatcher struct {
16+
events map[string]HTEvent
17+
mu sync.RWMutex
18+
}
19+
20+
// NewHTDispatcher creates a new event htDispatcher.
21+
func NewHTDispatcher() HTDispatcher {
22+
return &htDispatcher{
23+
events: map[string]HTEvent{},
24+
}
25+
}
26+
27+
func (t *htDispatcher) Handler(name string, args ...interface{}) error {
28+
t.mu.RLock()
29+
defer t.mu.RUnlock()
30+
31+
ev, ok := t.events[name]
32+
if !ok {
33+
return newHTEventNotDefined(name)
34+
}
35+
36+
return ev.Handler(args...)
37+
}
38+
39+
func (t *htDispatcher) On(name string, f interface{}) error {
40+
t.mu.Lock()
41+
defer t.mu.Unlock()
42+
43+
ev, ok := t.events[name]
44+
if !ok {
45+
ev = New()
46+
t.events[name] = ev
47+
}
48+
return ev.On(f)
49+
}
50+
51+
func (t *htDispatcher) Off(name string, f interface{}) error {
52+
t.mu.Lock()
53+
defer t.mu.Unlock()
54+
55+
e, ok := t.events[name]
56+
if !ok {
57+
return newHTEventNotDefined(name)
58+
}
59+
60+
return e.Off(f)
61+
}
62+
63+
func (t *htDispatcher) Destroy(name string) error {
64+
if _, ok := t.events[name]; !ok {
65+
return newHTEventNotDefined(name)
66+
}
67+
delete(t.events, name)
68+
return nil
69+
}
70+
71+
var _ HTDispatcher = &htDispatcher{}

‎htevent/hterrors.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package htevent
2+
3+
import "fmt"
4+
5+
// HTEventNotDefined is an error indicationg that the event has not been defined.
6+
type HTEventNotDefined struct {
7+
name string
8+
}
9+
10+
func newHTEventNotDefined(name string) *HTEventNotDefined {
11+
return &HTEventNotDefined{
12+
name: name,
13+
}
14+
}
15+
16+
func (e *HTEventNotDefined) Error() string {
17+
return fmt.Sprintf("%s event has not been defined yet.", e.name)
18+
}
19+
20+
// HTEventName return name of the event.
21+
func (e *HTEventNotDefined) HTEventName() string {
22+
return e.name
23+
}
24+
25+
var _ error = newHTEventNotDefined("none f")
26+

‎htevent/htevent.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package htevent
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
"sync"
7+
)
8+
9+
// HTEvent is an event.
10+
type HTEvent interface {
11+
Handler(args ...interface{}) error
12+
// f is a function
13+
On(f interface{}) error
14+
Off(f interface{}) error
15+
}
16+
17+
type event struct {
18+
// listeners are listener functions.
19+
listeners []reflect.Value
20+
lmu sync.RWMutex
21+
22+
argTypes []reflect.Type
23+
tmu sync.RWMutex
24+
}
25+
26+
// New creates a new event.
27+
func New() HTEvent {
28+
return &event{}
29+
}
30+
31+
var _ HTEvent = New()
32+
33+
func (p *event) Handler(args ...interface{}) error {
34+
35+
arguments := make([]reflect.Value, 0, len(args))
36+
argTypes := make([]reflect.Type, 0, len(args))
37+
for _, v := range args {
38+
arguments = append(arguments, reflect.ValueOf(v))
39+
argTypes = append(argTypes, reflect.TypeOf(v))
40+
}
41+
42+
err := p.validateArgs(argTypes)
43+
if err != nil {
44+
return err
45+
}
46+
47+
p.lmu.RLock()
48+
defer p.lmu.RUnlock()
49+
50+
wg := sync.WaitGroup{}
51+
wg.Add(len(p.listeners))
52+
for _, fn := range p.listeners {
53+
go func(f reflect.Value) {
54+
defer wg.Done()
55+
f.Call(arguments)
56+
}(fn)
57+
}
58+
59+
wg.Wait()
60+
return nil
61+
}
62+
63+
// Start to listen an event.
64+
func (p *event) On(f interface{}) error {
65+
fn, err := p.checkFuncSignature(f)
66+
if err != nil {
67+
return err
68+
}
69+
70+
p.lmu.Lock()
71+
defer p.lmu.Unlock()
72+
p.listeners = append(p.listeners, *fn)
73+
74+
return nil
75+
}
76+
77+
// Stop listening an event.
78+
func (p *event) Off(f interface{}) error {
79+
fn := reflect.ValueOf(f)
80+
81+
p.lmu.Lock()
82+
defer p.lmu.Unlock()
83+
l := len(p.listeners)
84+
m := l // for error check
85+
for i := 0; i < l; i++ {
86+
if fn == p.listeners[i] {
87+
// XXX: GC Ref: http://jxck.hatenablog.com/entry/golang-slice-internals
88+
p.listeners = append(p.listeners[:i], p.listeners[i+1:]...)
89+
l--
90+
i--
91+
}
92+
}
93+
94+
if l == m {
95+
return fmt.Errorf("Listener does't exists")
96+
}
97+
return nil
98+
}
99+
100+
// retrun function as reflect.Value
101+
// retrun error if f isn't function, argument is invalid
102+
func (p *event) checkFuncSignature(f interface{}) (*reflect.Value, error) {
103+
fn := reflect.ValueOf(f)
104+
if fn.Kind() != reflect.Func {
105+
return nil, fmt.Errorf("Argument should be a function")
106+
}
107+
108+
types := fnArgTypes(fn)
109+
110+
p.lmu.RLock()
111+
defer p.lmu.RUnlock()
112+
if len(p.listeners) == 0 {
113+
p.tmu.Lock()
114+
defer p.tmu.Unlock()
115+
p.argTypes = types
116+
return &fn, nil
117+
}
118+
119+
err := p.validateArgs(types)
120+
if err != nil {
121+
return nil, err
122+
}
123+
124+
return &fn, nil
125+
}
126+
127+
// if argument size or type are different return error.
128+
func (p *event) validateArgs(types []reflect.Type) error {
129+
p.tmu.RLock()
130+
defer p.tmu.RUnlock()
131+
if len(types) != len(p.argTypes) {
132+
return fmt.Errorf("Argument length expected %d, but got %d", len(p.argTypes), len(types))
133+
}
134+
for i, t := range types {
135+
if t != p.argTypes[i] {
136+
return fmt.Errorf("Argument Error. Args[%d] expected %s, but got %s", i, p.argTypes[i], t)
137+
}
138+
}
139+
140+
return nil
141+
}
142+
143+
// return argument types.
144+
func fnArgTypes(fn reflect.Value) []reflect.Type {
145+
fnType := fn.Type()
146+
fnNum := fnType.NumIn()
147+
148+
types := make([]reflect.Type, 0, fnNum)
149+
150+
for i := 0; i < fnNum; i++ {
151+
types = append(types, fnType.In(i))
152+
}
153+
154+
return types
155+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /