forked from toolshed/abra
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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,
 | 
						|
	}
 | 
						|
}
 |