trpc.group/trpc-go/trpc-go@v1.0.3/internal/httprule/template.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package httprule
    15  
    16  import (
    17  	"fmt"
    18  	"strings"
    19  )
    20  
    21  // PathTemplate URL path template:
    22  //
    23  // Template = "/" Segments [ Verb ] ;
    24  // Segments = Segment { "/" Segment } ;
    25  // Segment  = "*" | "**" | LITERAL | Variable ;
    26  // Variable = "{" FieldPath [ "=" Segments ] "}" ;
    27  // FieldPath = IDENT { "." IDENT } ;
    28  // Verb     = ":" LITERAL ;
    29  type PathTemplate struct {
    30  	segments []segment
    31  	verb     string
    32  }
    33  
    34  // segment type.
    35  type segmentKind int
    36  
    37  const (
    38  	kindWildcard segmentKind = iota
    39  	kindDeepWildcard
    40  	kindLiteral
    41  	kindVariable
    42  )
    43  
    44  // Segment = "*" | "**" | LITERAL | Variable
    45  type segment interface {
    46  	fmt.Stringer
    47  	handle(*matcher) error
    48  	kind() segmentKind
    49  	fieldPath() []string
    50  	nestedSegments() []segment
    51  }
    52  
    53  var _ segment = wildcard{}
    54  var _ segment = deepWildcard{}
    55  var _ segment = literal("")
    56  var _ segment = variable{}
    57  
    58  // wildcard represents *.
    59  type wildcard struct{}
    60  
    61  // String implements segment.
    62  func (wildcard) String() string {
    63  	return "*"
    64  }
    65  
    66  // fieldPath implements segment.
    67  func (wildcard) fieldPath() []string {
    68  	return nil
    69  }
    70  
    71  // kind implements segment.
    72  func (wildcard) kind() segmentKind {
    73  	return kindWildcard
    74  }
    75  
    76  // nestedSegments implements segment.
    77  func (wildcard) nestedSegments() []segment {
    78  	return nil
    79  }
    80  
    81  // deepWildcard represents **.
    82  type deepWildcard struct{}
    83  
    84  // String implements segment.
    85  func (deepWildcard) String() string {
    86  	return "**"
    87  }
    88  
    89  // fieldPath implements segment.
    90  func (deepWildcard) fieldPath() []string {
    91  	return nil
    92  }
    93  
    94  // kind implements segment.
    95  func (deepWildcard) kind() segmentKind {
    96  	return kindDeepWildcard
    97  }
    98  
    99  // nestedSegments implements segment.
   100  func (deepWildcard) nestedSegments() []segment {
   101  	return nil
   102  }
   103  
   104  // literal, example: /foo.
   105  type literal string
   106  
   107  // String implements segment.
   108  func (l literal) String() string {
   109  	return string(l)
   110  }
   111  
   112  // fieldPath implements segment.
   113  func (literal) fieldPath() []string {
   114  	return nil
   115  }
   116  
   117  // kind implements segment.
   118  func (literal) kind() segmentKind {
   119  	return kindLiteral
   120  }
   121  
   122  // nestedSegments implements segment.
   123  func (literal) nestedSegments() []segment {
   124  	return nil
   125  }
   126  
   127  // variable is like {var=*},Variable = "{" FieldPath [ "=" Segments ] "}"
   128  type variable struct {
   129  	fp       []string // FieldPath = IDENT { "." IDENT }
   130  	segments []segment
   131  }
   132  
   133  // String imeplemts segment.
   134  func (v variable) String() string {
   135  	ss := make([]string, len(v.segments))
   136  	for i := range v.segments {
   137  		ss[i] = v.segments[i].String()
   138  	}
   139  	return fmt.Sprintf("{%s=%s}", strings.Join(v.fp, "."), strings.Join(ss, "/"))
   140  }
   141  
   142  // fieldPath implements segment.
   143  func (v variable) fieldPath() []string {
   144  	return v.fp
   145  }
   146  
   147  // kind implements segment.
   148  func (variable) kind() segmentKind {
   149  	return kindVariable
   150  }
   151  
   152  // nestedSegments implements segment.
   153  func (v variable) nestedSegments() []segment {
   154  	return v.segments
   155  }
   156  
   157  // FieldPaths gets field paths.
   158  func (tpl *PathTemplate) FieldPaths() [][]string {
   159  	var fps [][]string
   160  	for _, segment := range tpl.segments {
   161  		if fp := segment.fieldPath(); fp != nil {
   162  			fps = append(fps, fp)
   163  		}
   164  	}
   165  	return fps
   166  }