118 lines
2.2 KiB
Go
118 lines
2.2 KiB
Go
package httprule
|
|
|
|
import (
|
|
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
|
)
|
|
|
|
const (
|
|
opcodeVersion = 1
|
|
)
|
|
|
|
// Template is a compiled representation of path templates.
|
|
type Template struct {
|
|
// Version is the version number of the format.
|
|
Version int
|
|
// OpCodes is a sequence of operations.
|
|
OpCodes []int
|
|
// Pool is a constant pool
|
|
Pool []string
|
|
// Verb is a VERB part in the template.
|
|
Verb string
|
|
// Fields is a list of field paths bound in this template.
|
|
Fields []string
|
|
// Original template (example: /v1/a_bit_of_everything)
|
|
Template string
|
|
}
|
|
|
|
// Compiler compiles utilities representation of path templates into marshallable operations.
|
|
// They can be unmarshalled by runtime.NewPattern.
|
|
type Compiler interface {
|
|
Compile() Template
|
|
}
|
|
|
|
type op struct {
|
|
// code is the opcode of the operation
|
|
code utilities.OpCode
|
|
|
|
// str is a string operand of the code.
|
|
// num is ignored if str is not empty.
|
|
str string
|
|
|
|
// num is a numeric operand of the code.
|
|
num int
|
|
}
|
|
|
|
func (w wildcard) compile() []op {
|
|
return []op{
|
|
{code: utilities.OpPush},
|
|
}
|
|
}
|
|
|
|
func (w deepWildcard) compile() []op {
|
|
return []op{
|
|
{code: utilities.OpPushM},
|
|
}
|
|
}
|
|
|
|
func (l literal) compile() []op {
|
|
return []op{
|
|
{
|
|
code: utilities.OpLitPush,
|
|
str: string(l),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (v variable) compile() []op {
|
|
var ops []op
|
|
for _, s := range v.segments {
|
|
ops = append(ops, s.compile()...)
|
|
}
|
|
ops = append(ops, op{
|
|
code: utilities.OpConcatN,
|
|
num: len(v.segments),
|
|
}, op{
|
|
code: utilities.OpCapture,
|
|
str: v.path,
|
|
})
|
|
|
|
return ops
|
|
}
|
|
|
|
func (t template) Compile() Template {
|
|
var rawOps []op
|
|
for _, s := range t.segments {
|
|
rawOps = append(rawOps, s.compile()...)
|
|
}
|
|
|
|
var (
|
|
ops []int
|
|
pool []string
|
|
fields []string
|
|
)
|
|
consts := make(map[string]int)
|
|
for _, op := range rawOps {
|
|
ops = append(ops, int(op.code))
|
|
if op.str == "" {
|
|
ops = append(ops, op.num)
|
|
} else {
|
|
if _, ok := consts[op.str]; !ok {
|
|
consts[op.str] = len(pool)
|
|
pool = append(pool, op.str)
|
|
}
|
|
ops = append(ops, consts[op.str])
|
|
}
|
|
if op.code == utilities.OpCapture {
|
|
fields = append(fields, op.str)
|
|
}
|
|
}
|
|
return Template{
|
|
Version: opcodeVersion,
|
|
OpCodes: ops,
|
|
Pool: pool,
|
|
Verb: t.verb,
|
|
Fields: fields,
|
|
Template: t.template,
|
|
}
|
|
}
|