| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- package router
- import (
- "fmt"
- "strings"
- )
- /* routeElement contains a pre-compiled route pattern */
- type routeElement struct {
- originalPath string
- parsedPath string
- parsedArgs int
- }
- /* Router object is safe for concurrent use after construction */
- type Router struct {
- urlMap map[string]routeElement
- }
- /* addRoute adds or sets routing element in urlMap */
- func (r *Router) addRoute(key string, path string) error {
- if _, ok := r.urlMap[key]; ok {
- return ErrKeyExists
- }
- /* pre-compile path and replace path values with %v */
- pathBuffer := strings.Builder{}
- pathBuffer.Grow(len(path))
- placeholderCount := 0
- for idx := 0; idx < len(path); {
- /* look for open bracket */
- if path[idx] == '{' {
- /* look for corresponding closing bracket */
- closing := strings.IndexByte(path[idx:], '}')
- if closing == -1 {
- /* broken pattern, fail */
- return ErrBrokenPattern
- }
- pathBuffer.WriteString("%v")
- placeholderCount++
- idx += closing + 1
- continue
- }
- pathBuffer.WriteByte(path[idx])
- idx++
- }
- /* save pre-compiled path */
- r.urlMap[key] = routeElement{
- originalPath: path,
- parsedPath: pathBuffer.String(),
- parsedArgs: placeholderCount,
- }
- return nil
- }
- /* Route returns path route by key */
- func (r *Router) Route(key string, args ...any) (string, error) {
- /* lookup path in the database */
- element, ok := r.urlMap[key]
- if !ok {
- return "", ErrMissingKey
- }
- /* return path unchanged if there are no arguments */
- if len(args) != element.parsedArgs {
- return "", ErrArgMismatch
- }
- return fmt.Sprintf(element.parsedPath, args...), nil
- }
- /* Pattern returns original path */
- func (r *Router) Pattern(key string) (string, error) {
- if element, ok := r.urlMap[key]; ok {
- return element.originalPath, nil
- }
- return "", ErrMissingKey
- }
|