diff --git a/router.go b/router.go index 3f2e095..dd0a6b9 100644 --- a/router.go +++ b/router.go @@ -1,6 +1,11 @@ package router -import "net/http" +import ( + "errors" + "fmt" + "net/http" + "strings" +) type route struct { method string @@ -8,9 +13,17 @@ type route struct { callback http.HandlerFunc } +type segment struct { + path string + methods map[string]bool + callback http.HandlerFunc + children map[string]*segment +} + // Router is the main router object that keeps track of an looks up routes. type Router struct { routes []route + lookup *segment } // NewRouter is a constructor for Router. @@ -20,7 +33,62 @@ func NewRouter() (r Router) { // AddRoute adds a new route with a corresponding callback to the router. func (r *Router) AddRoute(method string, path string, callback http.HandlerFunc) (err error) { - r.routes = append(r.routes, route{method, path, callback}) + keys := setupKeys(strings.Split(path, "/")) + if r.lookup == nil { + r.lookup = &segment{} + r.lookup.children = map[string]*segment{} + r.lookup.methods = map[string]bool{} + } + + curr := r.lookup + + fmt.Printf("Keys: %v", len(keys)) + + for _, key := range keys { + var seg segment + if child, ok := curr.children[key]; !ok { + seg = *newSegment(curr.path, key) + curr.children[key] = &seg + curr = &seg + } else { + curr = child + } + } + + if curr.methods[method] { + err = errors.New("path already exists") + } + + if err == nil { + curr.callback = callback + curr.methods[method] = true + r.routes = append(r.routes, route{method, path, callback}) + } + + return +} + +func addSegment(curr *segment, keys []string) (seg *segment) { + for _, key := range keys { + if child, ok := curr.children[key]; !ok { + seg = newSegment(curr.path, key) + curr.children[key] = seg + curr = seg + } else { + curr = child + } + } + + return +} + +func setupKeys(slice []string) (clean []string) { + clean = append(clean, "/") + for _, v := range slice { + if v != "" { + clean = append(clean, "/"+v) + } + } return } @@ -30,11 +98,21 @@ func (r *Router) Get(path string, callback http.HandlerFunc) { r.AddRoute(http.MethodGet, path, callback) } -// // Handle I don't know what this is yet, I assume it's called when there's a request -// func (r *Router) Handle(w http.ResponseWriter, req *http.Request) { -// return -// } - func (r Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } + +func newSegment(parentPath string, key string) (seg *segment) { + var path string + if parentPath == "/" { + path = key + } else { + path = parentPath + key + } + seg = &segment{} + seg.children = map[string]*segment{} + seg.methods = map[string]bool{} + seg.path = path + + return +} diff --git a/router_test.go b/router_test.go index 147eb87..bccc688 100644 --- a/router_test.go +++ b/router_test.go @@ -27,6 +27,16 @@ func TestAddRouter(t *testing.T) { if err != nil { t.Error("The route was not correctly added to the router: ", err) } + + checkLookup(r.lookup) +} + +func checkLookup(curr *segment) { + fmt.Printf("%p { path: %s, methods: %v, children: %v, callback: %p }\n", curr, curr.path, curr.methods, curr.children, curr.callback) + + for _, v := range curr.children { + checkLookup(v) + } } func addAndCheckRoute(r *Router, method string, path string, callback http.HandlerFunc, routeCounter *int) (err error) {