-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathr3.go
200 lines (170 loc) · 3.91 KB
/
r3.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// github.com/c9s/r3 binding for go
package r3
/*
#cgo LDFLAGS: -lr3
#include <r3/r3.h>
void * getData(route *r) {
return r->data;
}
void * getNodeData(node *n) {
return n->data;
}
int getVarsLength(match_entry *e) {
return e->vars->len;
}
int getRequestMethod(match_entry *e) {
return e->request_method;
}
const char* getVar(match_entry *e, int i) {
return e->vars->tokens[i];
}
node * treeMatchEntry(node* tree, match_entry* entry) {
return r3_tree_matchl(tree, entry->path, entry->path_len, entry);
}
*/
import "C"
import "unsafe"
import (
"errors"
)
var (
MethodGet Method = C.METHOD_GET
MethodPost Method = C.METHOD_POST
MethodPut Method = C.METHOD_PUT
MethodDelete Method = C.METHOD_DELETE
MethodPatch Method = C.METHOD_PATCH
MethodHead Method = C.METHOD_HEAD
MethodOptions Method = C.METHOD_OPTIONS
MethodAll Method = C.METHOD_GET | C.METHOD_POST | C.METHOD_PUT | C.METHOD_DELETE | C.METHOD_PATCH | C.METHOD_HEAD | C.METHOD_OPTIONS
)
type Method int
type Node struct {
node *C.node
datas []interface{}
}
type Data struct {
Value interface{}
}
type Tree Node
func (n *Node) Data() interface{} {
var p *Data
p = (*Data)(C.getNodeData(n.node))
return p.Value
}
// Create a new Tree
func NewTree(capacity int) *Tree {
var n *C.node
n = C.r3_tree_create(C.int(capacity))
t := &Tree{
node: n,
datas: make([]interface{}, 0, 10),
}
return t
}
// Insert route with method and arbitary data
func (n *Tree) InsertRoute(m Method, path string, data interface{}) {
d := &Data{
Value: data,
}
p := C.CString(path)
/* hold reference to d so that it's not GCed */
n.datas = append(n.datas, d)
C.r3_tree_insert_routel(n.node, C.int(m), p, C.int(C.strlen(p)), unsafe.Pointer(d))
}
// Insert path
func (n *Tree) InsertPath(path string, data interface{}) {
d := &Data{
Value: data,
}
/* hold reference to d so that it's not GCed */
n.datas = append(n.datas, d)
p := C.CString(path)
C.r3_tree_insert_pathl(n.node, p, C.int(C.strlen(p)), unsafe.Pointer(d))
}
// Compile the tree, returns error if any
func (n *Tree) Compile() error {
var err C.int
var errstr *C.char
err = C.r3_tree_compile(n.node, &errstr)
if err != 0 {
defer C.free(unsafe.Pointer(errstr))
return errors.New(C.GoString(errstr))
}
return nil
}
// Match a MatchEntry, returns a Route object if found, nil otherwise
func (n *Tree) MatchRoute(e *MatchEntry) *Route {
r := C.r3_tree_match_route(n.node, e.entry)
if r == nil {
return nil
}
return &Route{
route: r,
}
}
// Match a MatchEntry, returns a Node object if found, nil otherwise
func (n *Tree) MatchNode(e *MatchEntry) *Node {
ret := C.treeMatchEntry(n.node, e.entry)
if ret == nil {
return nil
}
return &Node{
node: ret,
}
}
// Free the memory of a tree
func (n *Tree) Free() {
C.r3_tree_free(n.node)
n.node = nil
n.datas = nil
}
// Dump tree to stdout
func (n *Tree) Dump() {
C.r3_tree_dump(n.node, 0)
}
type MatchEntry struct {
entry *C.match_entry
}
// creates a new MatchEntry
func NewMatchEntry(path string) *MatchEntry {
p := C.CString(path)
e := C.match_entry_createl(p, C.int(C.strlen(p)))
return &MatchEntry{
entry: e,
}
}
func (e *MatchEntry) RequestMethod() Method {
return Method(C.getRequestMethod(e.entry))
}
// Set request method of the entry
func (e *MatchEntry) SetRequestMethod(m Method) {
e.entry.request_method = C.int(m)
}
// Get tokens in the path
func (e *MatchEntry) Vars() []string {
var length int = int(C.getVarsLength(e.entry))
var tokens []string = make([]string, length)
for i := 0; i < length; i++ {
tokens[i] = C.GoString(C.getVar(e.entry, C.int(i)))
}
return tokens
}
// Free memory
func (e *MatchEntry) Free() {
C.match_entry_free(e.entry)
e.entry = nil
}
type Route struct {
route *C.route
}
// Returns data payload of the route
func (r *Route) Data() interface{} {
var p *Data
p = (*Data)(C.getData(r.route))
return p.Value
}
// Free memory
func (r *Route) Free() {
C.r3_route_free(r.route)
r.route = nil
}