1package httprule 2 3import ( 4 "github.com/grpc-ecosystem/grpc-gateway/utilities" 5) 6 7const ( 8 opcodeVersion = 1 9) 10 11// Template is a compiled representation of path templates. 12type 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. 29type Compiler interface { 30 Compile() Template 31} 32 33type 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 45func (w wildcard) compile() []op { 46 return []op{ 47 {code: utilities.OpPush}, 48 } 49} 50 51func (w deepWildcard) compile() []op { 52 return []op{ 53 {code: utilities.OpPushM}, 54 } 55} 56 57func (l literal) compile() []op { 58 return []op{ 59 { 60 code: utilities.OpLitPush, 61 str: string(l), 62 }, 63 } 64} 65 66func (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 82func (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 if _, ok := consts[op.str]; !ok { 100 consts[op.str] = len(pool) 101 pool = append(pool, op.str) 102 } 103 ops = append(ops, consts[op.str]) 104 } 105 if op.code == utilities.OpCapture { 106 fields = append(fields, op.str) 107 } 108 } 109 return Template{ 110 Version: opcodeVersion, 111 OpCodes: ops, 112 Pool: pool, 113 Verb: t.verb, 114 Fields: fields, 115 Template: t.template, 116 } 117} 118