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