compile.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package httprule
  2. import (
  3. "github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
  4. )
  5. const (
  6. opcodeVersion = 1
  7. )
  8. // Template is a compiled representation of path templates.
  9. type Template struct {
  10. // Version is the version number of the format.
  11. Version int
  12. // OpCodes is a sequence of operations.
  13. OpCodes []int
  14. // Pool is a constant pool
  15. Pool []string
  16. // Verb is a VERB part in the template.
  17. Verb string
  18. // Fields is a list of field paths bound in this template.
  19. Fields []string
  20. // Original template (example: /v1/a_bit_of_everything)
  21. Template string
  22. }
  23. // Compiler compiles utilities representation of path templates into marshallable operations.
  24. // They can be unmarshalled by runtime.NewPattern.
  25. type Compiler interface {
  26. Compile() Template
  27. }
  28. type op struct {
  29. // code is the opcode of the operation
  30. code utilities.OpCode
  31. // str is a string operand of the code.
  32. // num is ignored if str is not empty.
  33. str string
  34. // num is a numeric operand of the code.
  35. num int
  36. }
  37. func (w wildcard) compile() []op {
  38. return []op{
  39. {code: utilities.OpPush},
  40. }
  41. }
  42. func (w deepWildcard) compile() []op {
  43. return []op{
  44. {code: utilities.OpPushM},
  45. }
  46. }
  47. func (l literal) compile() []op {
  48. return []op{
  49. {
  50. code: utilities.OpLitPush,
  51. str: string(l),
  52. },
  53. }
  54. }
  55. func (v variable) compile() []op {
  56. var ops []op
  57. for _, s := range v.segments {
  58. ops = append(ops, s.compile()...)
  59. }
  60. ops = append(ops, op{
  61. code: utilities.OpConcatN,
  62. num: len(v.segments),
  63. }, op{
  64. code: utilities.OpCapture,
  65. str: v.path,
  66. })
  67. return ops
  68. }
  69. func (t template) Compile() Template {
  70. var rawOps []op
  71. for _, s := range t.segments {
  72. rawOps = append(rawOps, s.compile()...)
  73. }
  74. var (
  75. ops []int
  76. pool []string
  77. fields []string
  78. )
  79. consts := make(map[string]int)
  80. for _, op := range rawOps {
  81. ops = append(ops, int(op.code))
  82. if op.str == "" {
  83. ops = append(ops, op.num)
  84. } else {
  85. // eof segment literal represents the "/" path pattern
  86. if op.str == eof {
  87. op.str = ""
  88. }
  89. if _, ok := consts[op.str]; !ok {
  90. consts[op.str] = len(pool)
  91. pool = append(pool, op.str)
  92. }
  93. ops = append(ops, consts[op.str])
  94. }
  95. if op.code == utilities.OpCapture {
  96. fields = append(fields, op.str)
  97. }
  98. }
  99. return Template{
  100. Version: opcodeVersion,
  101. OpCodes: ops,
  102. Pool: pool,
  103. Verb: t.verb,
  104. Fields: fields,
  105. Template: t.template,
  106. }
  107. }