123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package httprule
- import (
- "github.com/grpc-ecosystem/grpc-gateway/v2/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 {
- // eof segment literal represents the "/" path pattern
- if op.str == eof {
- op.str = ""
- }
- 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,
- }
- }
|