rebase: bump k8s.io/kubernetes from 1.26.2 to 1.27.2

Bumps [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) from 1.26.2 to 1.27.2.
- [Release notes](https://github.com/kubernetes/kubernetes/releases)
- [Commits](https://github.com/kubernetes/kubernetes/compare/v1.26.2...v1.27.2)

---
updated-dependencies:
- dependency-name: k8s.io/kubernetes
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-05-29 21:03:29 +00:00
committed by mergify[bot]
parent 0e79135419
commit 07b05616a0
1072 changed files with 208716 additions and 198880 deletions

35
vendor/github.com/google/cel-go/common/BUILD.bazel generated vendored Normal file
View File

@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"cost.go",
"error.go",
"errors.go",
"location.go",
"source.go",
],
importpath = "github.com/google/cel-go/common",
deps = [
"//common/runes:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_x_text//width:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"errors_test.go",
"source_test.go",
],
embed = [
":go_default_library",
],
)

View File

@ -0,0 +1,31 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"container.go",
],
importpath = "github.com/google/cel-go/common/containers",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"container_test.go",
],
embed = [
":go_default_library",
],
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)

View File

@ -0,0 +1,316 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package containers defines types and functions for resolving qualified names within a namespace
// or type provided to CEL.
package containers
import (
"fmt"
"strings"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
var (
// DefaultContainer has an empty container name.
DefaultContainer *Container = nil
// Empty map to search for aliases when needed.
noAliases = make(map[string]string)
)
// NewContainer creates a new Container with the fully-qualified name.
func NewContainer(opts ...ContainerOption) (*Container, error) {
var c *Container
var err error
for _, opt := range opts {
c, err = opt(c)
if err != nil {
return nil, err
}
}
return c, nil
}
// Container holds a reference to an optional qualified container name and set of aliases.
//
// The program container can be used to simplify variable, function, and type specification within
// CEL programs and behaves more or less like a C++ namespace. See ResolveCandidateNames for more
// details.
type Container struct {
name string
aliases map[string]string
}
// Extend creates a new Container with the existing settings and applies a series of
// ContainerOptions to further configure the new container.
func (c *Container) Extend(opts ...ContainerOption) (*Container, error) {
if c == nil {
return NewContainer(opts...)
}
// Copy the name and aliases of the existing container.
ext := &Container{name: c.Name()}
if len(c.aliasSet()) > 0 {
aliasSet := make(map[string]string, len(c.aliasSet()))
for k, v := range c.aliasSet() {
aliasSet[k] = v
}
ext.aliases = aliasSet
}
// Apply the new options to the container.
var err error
for _, opt := range opts {
ext, err = opt(ext)
if err != nil {
return nil, err
}
}
return ext, nil
}
// Name returns the fully-qualified name of the container.
//
// The name may conceptually be a namespace, package, or type.
func (c *Container) Name() string {
if c == nil {
return ""
}
return c.name
}
// ResolveCandidateNames returns the candidates name of namespaced identifiers in C++ resolution
// order.
//
// Names which shadow other names are returned first. If a name includes a leading dot ('.'),
// the name is treated as an absolute identifier which cannot be shadowed.
//
// Given a container name a.b.c.M.N and a type name R.s, this will deliver in order:
//
// a.b.c.M.N.R.s
// a.b.c.M.R.s
// a.b.c.R.s
// a.b.R.s
// a.R.s
// R.s
//
// If aliases or abbreviations are configured for the container, then alias names will take
// precedence over containerized names.
func (c *Container) ResolveCandidateNames(name string) []string {
if strings.HasPrefix(name, ".") {
qn := name[1:]
alias, isAlias := c.findAlias(qn)
if isAlias {
return []string{alias}
}
return []string{qn}
}
alias, isAlias := c.findAlias(name)
if isAlias {
return []string{alias}
}
if c.Name() == "" {
return []string{name}
}
nextCont := c.Name()
candidates := []string{nextCont + "." + name}
for i := strings.LastIndex(nextCont, "."); i >= 0; i = strings.LastIndex(nextCont, ".") {
nextCont = nextCont[:i]
candidates = append(candidates, nextCont+"."+name)
}
return append(candidates, name)
}
// aliasSet returns the alias to fully-qualified name mapping stored in the container.
func (c *Container) aliasSet() map[string]string {
if c == nil || c.aliases == nil {
return noAliases
}
return c.aliases
}
// findAlias takes a name as input and returns an alias expansion if one exists.
//
// If the name is qualified, the first component of the qualified name is checked against known
// aliases. Any alias that is found in a qualified name is expanded in the result:
//
// alias: R -> my.alias.R
// name: R.S.T
// output: my.alias.R.S.T
//
// Note, the name must not have a leading dot.
func (c *Container) findAlias(name string) (string, bool) {
// If an alias exists for the name, ensure it is searched last.
simple := name
qualifier := ""
dot := strings.Index(name, ".")
if dot >= 0 {
simple = name[0:dot]
qualifier = name[dot:]
}
alias, found := c.aliasSet()[simple]
if !found {
return "", false
}
return alias + qualifier, true
}
// ContainerOption specifies a functional configuration option for a Container.
//
// Note, ContainerOption implementations must be able to handle nil container inputs.
type ContainerOption func(*Container) (*Container, error)
// Abbrevs configures a set of simple names as abbreviations for fully-qualified names.
//
// An abbreviation (abbrev for short) is a simple name that expands to a fully-qualified name.
// Abbreviations can be useful when working with variables, functions, and especially types from
// multiple namespaces:
//
// // CEL object construction
// qual.pkg.version.ObjTypeName{
// field: alt.container.ver.FieldTypeName{value: ...}
// }
//
// Only one the qualified names above may be used as the CEL container, so at least one of these
// references must be a long qualified name within an otherwise short CEL program. Using the
// following abbreviations, the program becomes much simpler:
//
// // CEL Go option
// Abbrevs("qual.pkg.version.ObjTypeName", "alt.container.ver.FieldTypeName")
// // Simplified Object construction
// ObjTypeName{field: FieldTypeName{value: ...}}
//
// There are a few rules for the qualified names and the simple abbreviations generated from them:
// - Qualified names must be dot-delimited, e.g. `package.subpkg.name`.
// - The last element in the qualified name is the abbreviation.
// - Abbreviations must not collide with each other.
// - The abbreviation must not collide with unqualified names in use.
//
// Abbreviations are distinct from container-based references in the following important ways:
// - Abbreviations must expand to a fully-qualified name.
// - Expanded abbreviations do not participate in namespace resolution.
// - Abbreviation expansion is done instead of the container search for a matching identifier.
// - Containers follow C++ namespace resolution rules with searches from the most qualified name
// to the least qualified name.
// - Container references within the CEL program may be relative, and are resolved to fully
// qualified names at either type-check time or program plan time, whichever comes first.
//
// If there is ever a case where an identifier could be in both the container and as an
// abbreviation, the abbreviation wins as this will ensure that the meaning of a program is
// preserved between compilations even as the container evolves.
func Abbrevs(qualifiedNames ...string) ContainerOption {
return func(c *Container) (*Container, error) {
for _, qn := range qualifiedNames {
ind := strings.LastIndex(qn, ".")
if ind <= 0 || ind >= len(qn)-1 {
return nil, fmt.Errorf(
"invalid qualified name: %s, wanted name of the form 'qualified.name'", qn)
}
alias := qn[ind+1:]
var err error
c, err = aliasAs("abbreviation", qn, alias)(c)
if err != nil {
return nil, err
}
}
return c, nil
}
}
// Alias associates a fully-qualified name with a user-defined alias.
//
// In general, Abbrevs is preferred to Alias since the names generated from the Abbrevs option
// are more easily traced back to source code. The Alias option is useful for propagating alias
// configuration from one Container instance to another, and may also be useful for remapping
// poorly chosen protobuf message / package names.
//
// Note: all of the rules that apply to Abbrevs also apply to Alias.
func Alias(qualifiedName, alias string) ContainerOption {
return aliasAs("alias", qualifiedName, alias)
}
func aliasAs(kind, qualifiedName, alias string) ContainerOption {
return func(c *Container) (*Container, error) {
if len(alias) == 0 || strings.Contains(alias, ".") {
return nil, fmt.Errorf(
"%s must be non-empty and simple (not qualified): %s=%s", kind, kind, alias)
}
if qualifiedName[0:1] == "." {
return nil, fmt.Errorf("qualified name must not begin with a leading '.': %s",
qualifiedName)
}
ind := strings.LastIndex(qualifiedName, ".")
if ind <= 0 || ind == len(qualifiedName)-1 {
return nil, fmt.Errorf("%s must refer to a valid qualified name: %s",
kind, qualifiedName)
}
aliasRef, found := c.aliasSet()[alias]
if found {
return nil, fmt.Errorf(
"%s collides with existing reference: name=%s, %s=%s, existing=%s",
kind, qualifiedName, kind, alias, aliasRef)
}
if strings.HasPrefix(c.Name(), alias+".") || c.Name() == alias {
return nil, fmt.Errorf(
"%s collides with container name: name=%s, %s=%s, container=%s",
kind, qualifiedName, kind, alias, c.Name())
}
if c == nil {
c = &Container{}
}
if c.aliases == nil {
c.aliases = make(map[string]string)
}
c.aliases[alias] = qualifiedName
return c, nil
}
}
// Name sets the fully-qualified name of the Container.
func Name(name string) ContainerOption {
return func(c *Container) (*Container, error) {
if len(name) > 0 && name[0:1] == "." {
return nil, fmt.Errorf("container name must not contain a leading '.': %s", name)
}
if c.Name() == name {
return c, nil
}
if c == nil {
return &Container{name: name}, nil
}
c.name = name
return c, nil
}
}
// ToQualifiedName converts an expression AST into a qualified name if possible, with a boolean
// 'found' value that indicates if the conversion is successful.
func ToQualifiedName(e *exprpb.Expr) (string, bool) {
switch e.GetExprKind().(type) {
case *exprpb.Expr_IdentExpr:
id := e.GetIdentExpr()
return id.GetName(), true
case *exprpb.Expr_SelectExpr:
sel := e.GetSelectExpr()
// Test only expressions are not valid as qualified names.
if sel.GetTestOnly() {
return "", false
}
if qual, found := ToQualifiedName(sel.GetOperand()); found {
return qual + "." + sel.GetField(), true
}
}
return "", false
}

40
vendor/github.com/google/cel-go/common/cost.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
const (
// SelectAndIdentCost is the cost of an operation that accesses an identifier or performs a select.
SelectAndIdentCost = 1
// ConstCost is the cost of an operation that accesses a constant.
ConstCost = 0
// ListCreateBaseCost is the base cost of any operation that creates a new list.
ListCreateBaseCost = 10
// MapCreateBaseCost is the base cost of any operation that creates a new map.
MapCreateBaseCost = 30
// StructCreateBaseCost is the base cost of any operation that creates a new struct.
StructCreateBaseCost = 40
// StringTraversalCostFactor is multiplied to a length of a string when computing the cost of traversing the entire
// string once.
StringTraversalCostFactor = 0.1
// RegexStringLengthCostFactor is multiplied ot the length of a regex string pattern when computing the cost of
// applying the regex to a string of unit cost.
RegexStringLengthCostFactor = 0.25
)

View File

@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"debug.go",
],
importpath = "github.com/google/cel-go/common/debug",
deps = [
"//common:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)

305
vendor/github.com/google/cel-go/common/debug/debug.go generated vendored Normal file
View File

@ -0,0 +1,305 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package debug provides tools to print a parsed expression graph and
// adorn each expression element with additional metadata.
package debug
import (
"bytes"
"fmt"
"strconv"
"strings"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Adorner returns debug metadata that will be tacked on to the string
// representation of an expression.
type Adorner interface {
// GetMetadata for the input context.
GetMetadata(ctx interface{}) string
}
// Writer manages writing expressions to an internal string.
type Writer interface {
fmt.Stringer
// Buffer pushes an expression into an internal queue of expressions to
// write to a string.
Buffer(e *exprpb.Expr)
}
type emptyDebugAdorner struct {
}
var emptyAdorner Adorner = &emptyDebugAdorner{}
func (a *emptyDebugAdorner) GetMetadata(e interface{}) string {
return ""
}
// ToDebugString gives the unadorned string representation of the Expr.
func ToDebugString(e *exprpb.Expr) string {
return ToAdornedDebugString(e, emptyAdorner)
}
// ToAdornedDebugString gives the adorned string representation of the Expr.
func ToAdornedDebugString(e *exprpb.Expr, adorner Adorner) string {
w := newDebugWriter(adorner)
w.Buffer(e)
return w.String()
}
// debugWriter is used to print out pretty-printed debug strings.
type debugWriter struct {
adorner Adorner
buffer bytes.Buffer
indent int
lineStart bool
}
func newDebugWriter(a Adorner) *debugWriter {
return &debugWriter{
adorner: a,
indent: 0,
lineStart: true,
}
}
func (w *debugWriter) Buffer(e *exprpb.Expr) {
if e == nil {
return
}
switch e.ExprKind.(type) {
case *exprpb.Expr_ConstExpr:
w.append(formatLiteral(e.GetConstExpr()))
case *exprpb.Expr_IdentExpr:
w.append(e.GetIdentExpr().Name)
case *exprpb.Expr_SelectExpr:
w.appendSelect(e.GetSelectExpr())
case *exprpb.Expr_CallExpr:
w.appendCall(e.GetCallExpr())
case *exprpb.Expr_ListExpr:
w.appendList(e.GetListExpr())
case *exprpb.Expr_StructExpr:
w.appendStruct(e.GetStructExpr())
case *exprpb.Expr_ComprehensionExpr:
w.appendComprehension(e.GetComprehensionExpr())
}
w.adorn(e)
}
func (w *debugWriter) appendSelect(sel *exprpb.Expr_Select) {
w.Buffer(sel.GetOperand())
w.append(".")
w.append(sel.GetField())
if sel.TestOnly {
w.append("~test-only~")
}
}
func (w *debugWriter) appendCall(call *exprpb.Expr_Call) {
if call.Target != nil {
w.Buffer(call.GetTarget())
w.append(".")
}
w.append(call.GetFunction())
w.append("(")
if len(call.GetArgs()) > 0 {
w.addIndent()
w.appendLine()
for i, arg := range call.GetArgs() {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(arg)
}
w.removeIndent()
w.appendLine()
}
w.append(")")
}
func (w *debugWriter) appendList(list *exprpb.Expr_CreateList) {
w.append("[")
if len(list.GetElements()) > 0 {
w.appendLine()
w.addIndent()
for i, elem := range list.GetElements() {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(elem)
}
w.removeIndent()
w.appendLine()
}
w.append("]")
}
func (w *debugWriter) appendStruct(obj *exprpb.Expr_CreateStruct) {
if obj.MessageName != "" {
w.appendObject(obj)
} else {
w.appendMap(obj)
}
}
func (w *debugWriter) appendObject(obj *exprpb.Expr_CreateStruct) {
w.append(obj.GetMessageName())
w.append("{")
if len(obj.GetEntries()) > 0 {
w.appendLine()
w.addIndent()
for i, entry := range obj.GetEntries() {
if i > 0 {
w.append(",")
w.appendLine()
}
w.append(entry.GetFieldKey())
w.append(":")
w.Buffer(entry.GetValue())
w.adorn(entry)
}
w.removeIndent()
w.appendLine()
}
w.append("}")
}
func (w *debugWriter) appendMap(obj *exprpb.Expr_CreateStruct) {
w.append("{")
if len(obj.GetEntries()) > 0 {
w.appendLine()
w.addIndent()
for i, entry := range obj.GetEntries() {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(entry.GetMapKey())
w.append(":")
w.Buffer(entry.GetValue())
w.adorn(entry)
}
w.removeIndent()
w.appendLine()
}
w.append("}")
}
func (w *debugWriter) appendComprehension(comprehension *exprpb.Expr_Comprehension) {
w.append("__comprehension__(")
w.addIndent()
w.appendLine()
w.append("// Variable")
w.appendLine()
w.append(comprehension.GetIterVar())
w.append(",")
w.appendLine()
w.append("// Target")
w.appendLine()
w.Buffer(comprehension.GetIterRange())
w.append(",")
w.appendLine()
w.append("// Accumulator")
w.appendLine()
w.append(comprehension.GetAccuVar())
w.append(",")
w.appendLine()
w.append("// Init")
w.appendLine()
w.Buffer(comprehension.GetAccuInit())
w.append(",")
w.appendLine()
w.append("// LoopCondition")
w.appendLine()
w.Buffer(comprehension.GetLoopCondition())
w.append(",")
w.appendLine()
w.append("// LoopStep")
w.appendLine()
w.Buffer(comprehension.GetLoopStep())
w.append(",")
w.appendLine()
w.append("// Result")
w.appendLine()
w.Buffer(comprehension.GetResult())
w.append(")")
w.removeIndent()
}
func formatLiteral(c *exprpb.Constant) string {
switch c.GetConstantKind().(type) {
case *exprpb.Constant_BoolValue:
return fmt.Sprintf("%t", c.GetBoolValue())
case *exprpb.Constant_BytesValue:
return fmt.Sprintf("b\"%s\"", string(c.GetBytesValue()))
case *exprpb.Constant_DoubleValue:
return fmt.Sprintf("%v", c.GetDoubleValue())
case *exprpb.Constant_Int64Value:
return fmt.Sprintf("%d", c.GetInt64Value())
case *exprpb.Constant_StringValue:
return strconv.Quote(c.GetStringValue())
case *exprpb.Constant_Uint64Value:
return fmt.Sprintf("%du", c.GetUint64Value())
case *exprpb.Constant_NullValue:
return "null"
default:
panic("Unknown constant type")
}
}
func (w *debugWriter) append(s string) {
w.doIndent()
w.buffer.WriteString(s)
}
func (w *debugWriter) appendFormat(f string, args ...interface{}) {
w.append(fmt.Sprintf(f, args...))
}
func (w *debugWriter) doIndent() {
if w.lineStart {
w.lineStart = false
w.buffer.WriteString(strings.Repeat(" ", w.indent))
}
}
func (w *debugWriter) adorn(e interface{}) {
w.append(w.adorner.GetMetadata(e))
}
func (w *debugWriter) appendLine() {
w.buffer.WriteString("\n")
w.lineStart = true
}
func (w *debugWriter) addIndent() {
w.indent++
}
func (w *debugWriter) removeIndent() {
w.indent--
if w.indent < 0 {
panic("negative indent")
}
}
func (w *debugWriter) String() string {
return w.buffer.String()
}

17
vendor/github.com/google/cel-go/common/doc.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package common defines types and utilities common to expression parsing,
// checking, and interpretation
package common

73
vendor/github.com/google/cel-go/common/error.go generated vendored Normal file
View File

@ -0,0 +1,73 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
import (
"fmt"
"strings"
"unicode/utf8"
"golang.org/x/text/width"
)
// Error type which references a location within source and a message.
type Error struct {
Location Location
Message string
}
const (
dot = "."
ind = "^"
// maxSnippetLength is the largest number of characters which can be rendered in an error message snippet.
maxSnippetLength = 16384
)
var (
wideDot = width.Widen.String(dot)
wideInd = width.Widen.String(ind)
)
// ToDisplayString decorates the error message with the source location.
func (e *Error) ToDisplayString(source Source) string {
var result = fmt.Sprintf("ERROR: %s:%d:%d: %s",
source.Description(),
e.Location.Line(),
e.Location.Column()+1, // add one to the 0-based column for display
e.Message)
if snippet, found := source.Snippet(e.Location.Line()); found && len(snippet) <= maxSnippetLength {
snippet := strings.Replace(snippet, "\t", " ", -1)
srcLine := "\n | " + snippet
var bytes = []byte(snippet)
var indLine = "\n | "
for i := 0; i < e.Location.Column() && len(bytes) > 0; i++ {
_, sz := utf8.DecodeRune(bytes)
bytes = bytes[sz:]
if sz > 1 {
indLine += wideDot
} else {
indLine += dot
}
}
if _, sz := utf8.DecodeRune(bytes); sz > 1 {
indLine += wideInd
} else {
indLine += ind
}
result += srcLine + indLine
}
return result
}

97
vendor/github.com/google/cel-go/common/errors.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
import (
"fmt"
"sort"
"strings"
)
// Errors type which contains a list of errors observed during parsing.
type Errors struct {
errors []Error
source Source
numErrors int
maxErrorsToReport int
}
// NewErrors creates a new instance of the Errors type.
func NewErrors(source Source) *Errors {
return &Errors{
errors: []Error{},
source: source,
maxErrorsToReport: 100,
}
}
// ReportError records an error at a source location.
func (e *Errors) ReportError(l Location, format string, args ...interface{}) {
e.numErrors++
if e.numErrors > e.maxErrorsToReport {
return
}
err := Error{
Location: l,
Message: fmt.Sprintf(format, args...),
}
e.errors = append(e.errors, err)
}
// GetErrors returns the list of observed errors.
func (e *Errors) GetErrors() []Error {
return e.errors[:]
}
// Append creates a new Errors object with the current and input errors.
func (e *Errors) Append(errs []Error) *Errors {
return &Errors{
errors: append(e.errors, errs...),
source: e.source,
numErrors: e.numErrors + len(errs),
maxErrorsToReport: e.maxErrorsToReport,
}
}
// ToDisplayString returns the error set to a newline delimited string.
func (e *Errors) ToDisplayString() string {
errorsInString := e.maxErrorsToReport
if e.numErrors > e.maxErrorsToReport {
// add one more error to indicate the number of errors truncated.
errorsInString++
} else {
// otherwise the error set will just contain the number of errors.
errorsInString = e.numErrors
}
result := make([]string, errorsInString)
sort.SliceStable(e.errors, func(i, j int) bool {
ei := e.errors[i].Location
ej := e.errors[j].Location
return ei.Line() < ej.Line() ||
(ei.Line() == ej.Line() && ei.Column() < ej.Column())
})
for i, err := range e.errors {
// This can happen during the append of two errors objects
if i >= e.maxErrorsToReport {
break
}
result[i] = err.ToDisplayString(e.source)
}
if e.numErrors > e.maxErrorsToReport {
result[e.maxErrorsToReport] = fmt.Sprintf("%d more errors were truncated", e.numErrors-e.maxErrorsToReport)
}
return strings.Join(result, "\n")
}

51
vendor/github.com/google/cel-go/common/location.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
// Location interface to represent a location within Source.
type Location interface {
Line() int // 1-based line number within source.
Column() int // 0-based column number within source.
}
// SourceLocation helper type to manually construct a location.
type SourceLocation struct {
line int
column int
}
var (
// Location implements the SourceLocation interface.
_ Location = &SourceLocation{}
// NoLocation is a particular illegal location.
NoLocation = &SourceLocation{-1, -1}
)
// NewLocation creates a new location.
func NewLocation(line, column int) Location {
return &SourceLocation{
line: line,
column: column}
}
// Line returns the 1-based line of the location.
func (l *SourceLocation) Line() int {
return l.line
}
// Column returns the 0-based column number of the location.
func (l *SourceLocation) Column() int {
return l.column
}

View File

@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"operators.go",
],
importpath = "github.com/google/cel-go/common/operators",
)

View File

@ -0,0 +1,153 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package operators defines the internal function names of operators.
//
// All operators in the expression language are modelled as function calls.
package operators
// String "names" for CEL operators.
const (
// Symbolic operators.
Conditional = "_?_:_"
LogicalAnd = "_&&_"
LogicalOr = "_||_"
LogicalNot = "!_"
Equals = "_==_"
NotEquals = "_!=_"
Less = "_<_"
LessEquals = "_<=_"
Greater = "_>_"
GreaterEquals = "_>=_"
Add = "_+_"
Subtract = "_-_"
Multiply = "_*_"
Divide = "_/_"
Modulo = "_%_"
Negate = "-_"
Index = "_[_]"
// Macros, must have a valid identifier.
Has = "has"
All = "all"
Exists = "exists"
ExistsOne = "exists_one"
Map = "map"
Filter = "filter"
// Named operators, must not have be valid identifiers.
NotStrictlyFalse = "@not_strictly_false"
In = "@in"
// Deprecated: named operators with valid identifiers.
OldNotStrictlyFalse = "__not_strictly_false__"
OldIn = "_in_"
)
var (
operators = map[string]string{
"+": Add,
"/": Divide,
"==": Equals,
">": Greater,
">=": GreaterEquals,
"in": In,
"<": Less,
"<=": LessEquals,
"%": Modulo,
"*": Multiply,
"!=": NotEquals,
"-": Subtract,
}
// operatorMap of the operator symbol which refers to a struct containing the display name,
// if applicable, the operator precedence, and the arity.
//
// If the symbol does not have a display name listed in the map, it is only because it requires
// special casing to render properly as text.
operatorMap = map[string]struct {
displayName string
precedence int
arity int
}{
Conditional: {displayName: "", precedence: 8, arity: 3},
LogicalOr: {displayName: "||", precedence: 7, arity: 2},
LogicalAnd: {displayName: "&&", precedence: 6, arity: 2},
Equals: {displayName: "==", precedence: 5, arity: 2},
Greater: {displayName: ">", precedence: 5, arity: 2},
GreaterEquals: {displayName: ">=", precedence: 5, arity: 2},
In: {displayName: "in", precedence: 5, arity: 2},
Less: {displayName: "<", precedence: 5, arity: 2},
LessEquals: {displayName: "<=", precedence: 5, arity: 2},
NotEquals: {displayName: "!=", precedence: 5, arity: 2},
OldIn: {displayName: "in", precedence: 5, arity: 2},
Add: {displayName: "+", precedence: 4, arity: 2},
Subtract: {displayName: "-", precedence: 4, arity: 2},
Divide: {displayName: "/", precedence: 3, arity: 2},
Modulo: {displayName: "%", precedence: 3, arity: 2},
Multiply: {displayName: "*", precedence: 3, arity: 2},
LogicalNot: {displayName: "!", precedence: 2, arity: 1},
Negate: {displayName: "-", precedence: 2, arity: 1},
Index: {displayName: "", precedence: 1, arity: 2},
}
)
// Find the internal function name for an operator, if the input text is one.
func Find(text string) (string, bool) {
op, found := operators[text]
return op, found
}
// FindReverse returns the unmangled, text representation of the operator.
func FindReverse(symbol string) (string, bool) {
op, found := operatorMap[symbol]
if !found {
return "", false
}
return op.displayName, true
}
// FindReverseBinaryOperator returns the unmangled, text representation of a binary operator.
//
// If the symbol does refer to an operator, but the operator does not have a display name the
// result is false.
func FindReverseBinaryOperator(symbol string) (string, bool) {
op, found := operatorMap[symbol]
if !found || op.arity != 2 {
return "", false
}
if op.displayName == "" {
return "", false
}
return op.displayName, true
}
// Precedence returns the operator precedence, where the higher the number indicates
// higher precedence operations.
func Precedence(symbol string) int {
op, found := operatorMap[symbol]
if !found {
return 0
}
return op.precedence
}
// Arity returns the number of argument the operator takes
// -1 is returned if an undefined symbol is provided
func Arity(symbol string) int {
op, found := operatorMap[symbol]
if !found {
return -1
}
return op.arity
}

View File

@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"overloads.go",
],
importpath = "github.com/google/cel-go/common/overloads",
)

View File

@ -0,0 +1,317 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package overloads defines the internal overload identifiers for function and
// operator overloads.
package overloads
// Boolean logic overloads
const (
Conditional = "conditional"
LogicalAnd = "logical_and"
LogicalOr = "logical_or"
LogicalNot = "logical_not"
NotStrictlyFalse = "not_strictly_false"
Equals = "equals"
NotEquals = "not_equals"
LessBool = "less_bool"
LessInt64 = "less_int64"
LessInt64Double = "less_int64_double"
LessInt64Uint64 = "less_int64_uint64"
LessUint64 = "less_uint64"
LessUint64Double = "less_uint64_double"
LessUint64Int64 = "less_uint64_int64"
LessDouble = "less_double"
LessDoubleInt64 = "less_double_int64"
LessDoubleUint64 = "less_double_uint64"
LessString = "less_string"
LessBytes = "less_bytes"
LessTimestamp = "less_timestamp"
LessDuration = "less_duration"
LessEqualsBool = "less_equals_bool"
LessEqualsInt64 = "less_equals_int64"
LessEqualsInt64Double = "less_equals_int64_double"
LessEqualsInt64Uint64 = "less_equals_int64_uint64"
LessEqualsUint64 = "less_equals_uint64"
LessEqualsUint64Double = "less_equals_uint64_double"
LessEqualsUint64Int64 = "less_equals_uint64_int64"
LessEqualsDouble = "less_equals_double"
LessEqualsDoubleInt64 = "less_equals_double_int64"
LessEqualsDoubleUint64 = "less_equals_double_uint64"
LessEqualsString = "less_equals_string"
LessEqualsBytes = "less_equals_bytes"
LessEqualsTimestamp = "less_equals_timestamp"
LessEqualsDuration = "less_equals_duration"
GreaterBool = "greater_bool"
GreaterInt64 = "greater_int64"
GreaterInt64Double = "greater_int64_double"
GreaterInt64Uint64 = "greater_int64_uint64"
GreaterUint64 = "greater_uint64"
GreaterUint64Double = "greater_uint64_double"
GreaterUint64Int64 = "greater_uint64_int64"
GreaterDouble = "greater_double"
GreaterDoubleInt64 = "greater_double_int64"
GreaterDoubleUint64 = "greater_double_uint64"
GreaterString = "greater_string"
GreaterBytes = "greater_bytes"
GreaterTimestamp = "greater_timestamp"
GreaterDuration = "greater_duration"
GreaterEqualsBool = "greater_equals_bool"
GreaterEqualsInt64 = "greater_equals_int64"
GreaterEqualsInt64Double = "greater_equals_int64_double"
GreaterEqualsInt64Uint64 = "greater_equals_int64_uint64"
GreaterEqualsUint64 = "greater_equals_uint64"
GreaterEqualsUint64Double = "greater_equals_uint64_double"
GreaterEqualsUint64Int64 = "greater_equals_uint64_int64"
GreaterEqualsDouble = "greater_equals_double"
GreaterEqualsDoubleInt64 = "greater_equals_double_int64"
GreaterEqualsDoubleUint64 = "greater_equals_double_uint64"
GreaterEqualsString = "greater_equals_string"
GreaterEqualsBytes = "greater_equals_bytes"
GreaterEqualsTimestamp = "greater_equals_timestamp"
GreaterEqualsDuration = "greater_equals_duration"
)
// Math overloads
const (
AddInt64 = "add_int64"
AddUint64 = "add_uint64"
AddDouble = "add_double"
AddString = "add_string"
AddBytes = "add_bytes"
AddList = "add_list"
AddTimestampDuration = "add_timestamp_duration"
AddDurationTimestamp = "add_duration_timestamp"
AddDurationDuration = "add_duration_duration"
SubtractInt64 = "subtract_int64"
SubtractUint64 = "subtract_uint64"
SubtractDouble = "subtract_double"
SubtractTimestampTimestamp = "subtract_timestamp_timestamp"
SubtractTimestampDuration = "subtract_timestamp_duration"
SubtractDurationDuration = "subtract_duration_duration"
MultiplyInt64 = "multiply_int64"
MultiplyUint64 = "multiply_uint64"
MultiplyDouble = "multiply_double"
DivideInt64 = "divide_int64"
DivideUint64 = "divide_uint64"
DivideDouble = "divide_double"
ModuloInt64 = "modulo_int64"
ModuloUint64 = "modulo_uint64"
NegateInt64 = "negate_int64"
NegateDouble = "negate_double"
)
// Index overloads
const (
IndexList = "index_list"
IndexMap = "index_map"
IndexMessage = "index_message" // TODO: introduce concept of types.Message
)
// In operators
const (
DeprecatedIn = "in"
InList = "in_list"
InMap = "in_map"
InMessage = "in_message" // TODO: introduce concept of types.Message
)
// Size overloads
const (
Size = "size"
SizeString = "size_string"
SizeBytes = "size_bytes"
SizeList = "size_list"
SizeMap = "size_map"
SizeStringInst = "string_size"
SizeBytesInst = "bytes_size"
SizeListInst = "list_size"
SizeMapInst = "map_size"
)
// String function names.
const (
Contains = "contains"
EndsWith = "endsWith"
Matches = "matches"
StartsWith = "startsWith"
)
// String function overload names.
const (
ContainsString = "contains_string"
EndsWithString = "ends_with_string"
MatchesString = "matches_string"
StartsWithString = "starts_with_string"
)
// Time-based functions.
const (
TimeGetFullYear = "getFullYear"
TimeGetMonth = "getMonth"
TimeGetDayOfYear = "getDayOfYear"
TimeGetDate = "getDate"
TimeGetDayOfMonth = "getDayOfMonth"
TimeGetDayOfWeek = "getDayOfWeek"
TimeGetHours = "getHours"
TimeGetMinutes = "getMinutes"
TimeGetSeconds = "getSeconds"
TimeGetMilliseconds = "getMilliseconds"
)
// Timestamp overloads for time functions without timezones.
const (
TimestampToYear = "timestamp_to_year"
TimestampToMonth = "timestamp_to_month"
TimestampToDayOfYear = "timestamp_to_day_of_year"
TimestampToDayOfMonthZeroBased = "timestamp_to_day_of_month"
TimestampToDayOfMonthOneBased = "timestamp_to_day_of_month_1_based"
TimestampToDayOfWeek = "timestamp_to_day_of_week"
TimestampToHours = "timestamp_to_hours"
TimestampToMinutes = "timestamp_to_minutes"
TimestampToSeconds = "timestamp_to_seconds"
TimestampToMilliseconds = "timestamp_to_milliseconds"
)
// Timestamp overloads for time functions with timezones.
const (
TimestampToYearWithTz = "timestamp_to_year_with_tz"
TimestampToMonthWithTz = "timestamp_to_month_with_tz"
TimestampToDayOfYearWithTz = "timestamp_to_day_of_year_with_tz"
TimestampToDayOfMonthZeroBasedWithTz = "timestamp_to_day_of_month_with_tz"
TimestampToDayOfMonthOneBasedWithTz = "timestamp_to_day_of_month_1_based_with_tz"
TimestampToDayOfWeekWithTz = "timestamp_to_day_of_week_with_tz"
TimestampToHoursWithTz = "timestamp_to_hours_with_tz"
TimestampToMinutesWithTz = "timestamp_to_minutes_with_tz"
TimestampToSecondsWithTz = "timestamp_to_seconds_tz"
TimestampToMillisecondsWithTz = "timestamp_to_milliseconds_with_tz"
)
// Duration overloads for time functions.
const (
DurationToHours = "duration_to_hours"
DurationToMinutes = "duration_to_minutes"
DurationToSeconds = "duration_to_seconds"
DurationToMilliseconds = "duration_to_milliseconds"
)
// Type conversion methods and overloads
const (
TypeConvertInt = "int"
TypeConvertUint = "uint"
TypeConvertDouble = "double"
TypeConvertBool = "bool"
TypeConvertString = "string"
TypeConvertBytes = "bytes"
TypeConvertTimestamp = "timestamp"
TypeConvertDuration = "duration"
TypeConvertType = "type"
TypeConvertDyn = "dyn"
)
// Int conversion functions.
const (
IntToInt = "int64_to_int64"
UintToInt = "uint64_to_int64"
DoubleToInt = "double_to_int64"
StringToInt = "string_to_int64"
TimestampToInt = "timestamp_to_int64"
DurationToInt = "duration_to_int64"
)
// Uint conversion functions.
const (
UintToUint = "uint64_to_uint64"
IntToUint = "int64_to_uint64"
DoubleToUint = "double_to_uint64"
StringToUint = "string_to_uint64"
)
// Double conversion functions.
const (
DoubleToDouble = "double_to_double"
IntToDouble = "int64_to_double"
UintToDouble = "uint64_to_double"
StringToDouble = "string_to_double"
)
// Bool conversion functions.
const (
BoolToBool = "bool_to_bool"
StringToBool = "string_to_bool"
)
// Bytes conversion functions.
const (
BytesToBytes = "bytes_to_bytes"
StringToBytes = "string_to_bytes"
)
// String conversion functions.
const (
StringToString = "string_to_string"
BoolToString = "bool_to_string"
IntToString = "int64_to_string"
UintToString = "uint64_to_string"
DoubleToString = "double_to_string"
BytesToString = "bytes_to_string"
TimestampToString = "timestamp_to_string"
DurationToString = "duration_to_string"
)
// Timestamp conversion functions
const (
TimestampToTimestamp = "timestamp_to_timestamp"
StringToTimestamp = "string_to_timestamp"
IntToTimestamp = "int64_to_timestamp"
)
// Convert duration from string
const (
DurationToDuration = "duration_to_duration"
StringToDuration = "string_to_duration"
IntToDuration = "int64_to_duration"
)
// Convert to dyn
const (
ToDyn = "to_dyn"
)
// Comprehensions helper methods, not directly accessible via a developer.
const (
Iterator = "@iterator"
HasNext = "@hasNext"
Next = "@next"
)
// IsTypeConversionFunction returns whether the input function is a standard library type
// conversion function.
func IsTypeConversionFunction(function string) bool {
switch function {
case TypeConvertBool,
TypeConvertBytes,
TypeConvertDouble,
TypeConvertDuration,
TypeConvertDyn,
TypeConvertInt,
TypeConvertString,
TypeConvertTimestamp,
TypeConvertType,
TypeConvertUint:
return true
default:
return false
}
}

View File

@ -0,0 +1,25 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"buffer.go",
],
importpath = "github.com/google/cel-go/common/runes",
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"buffer_test.go",
],
embed = [
":go_default_library",
],
)

194
vendor/github.com/google/cel-go/common/runes/buffer.go generated vendored Normal file
View File

@ -0,0 +1,194 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package runes provides interfaces and utilities for working with runes.
package runes
import (
"strings"
"unicode/utf8"
)
// Buffer is an interface for accessing a contiguous array of code points.
type Buffer interface {
Get(i int) rune
Slice(i, j int) string
Len() int
}
type emptyBuffer struct{}
func (e *emptyBuffer) Get(i int) rune {
panic("slice index out of bounds")
}
func (e *emptyBuffer) Slice(i, j int) string {
if i != 0 || i != j {
panic("slice index out of bounds")
}
return ""
}
func (e *emptyBuffer) Len() int {
return 0
}
var _ Buffer = &emptyBuffer{}
// asciiBuffer is an implementation for an array of code points that contain code points only from
// the ASCII character set.
type asciiBuffer struct {
arr []byte
}
func (a *asciiBuffer) Get(i int) rune {
return rune(uint32(a.arr[i]))
}
func (a *asciiBuffer) Slice(i, j int) string {
return string(a.arr[i:j])
}
func (a *asciiBuffer) Len() int {
return len(a.arr)
}
var _ Buffer = &asciiBuffer{}
// basicBuffer is an implementation for an array of code points that contain code points from both
// the Latin-1 character set and Basic Multilingual Plane.
type basicBuffer struct {
arr []uint16
}
func (b *basicBuffer) Get(i int) rune {
return rune(uint32(b.arr[i]))
}
func (b *basicBuffer) Slice(i, j int) string {
var str strings.Builder
str.Grow((j - i) * 3) // Worst case encoding size for 0xffff is 3.
for ; i < j; i++ {
str.WriteRune(rune(uint32(b.arr[i])))
}
return str.String()
}
func (b *basicBuffer) Len() int {
return len(b.arr)
}
var _ Buffer = &basicBuffer{}
// supplementalBuffer is an implementation for an array of code points that contain code points from
// the Latin-1 character set, Basic Multilingual Plane, or the Supplemental Multilingual Plane.
type supplementalBuffer struct {
arr []rune
}
func (s *supplementalBuffer) Get(i int) rune {
return rune(uint32(s.arr[i]))
}
func (s *supplementalBuffer) Slice(i, j int) string {
return string(s.arr[i:j])
}
func (s *supplementalBuffer) Len() int {
return len(s.arr)
}
var _ Buffer = &supplementalBuffer{}
var nilBuffer = &emptyBuffer{}
// NewBuffer returns an efficient implementation of Buffer for the given text based on the ranges of
// the encoded code points contained within.
//
// Code points are represented as an array of byte, uint16, or rune. This approach ensures that
// each index represents a code point by itself without needing to use an array of rune. At first
// we assume all code points are less than or equal to '\u007f'. If this holds true, the
// underlying storage is a byte array containing only ASCII characters. If we encountered a code
// point above this range but less than or equal to '\uffff' we allocate a uint16 array, copy the
// elements of previous byte array to the uint16 array, and continue. If this holds true, the
// underlying storage is a uint16 array containing only Unicode characters in the Basic Multilingual
// Plane. If we encounter a code point above '\uffff' we allocate an rune array, copy the previous
// elements of the byte or uint16 array, and continue. The underlying storage is an rune array
// containing any Unicode character.
func NewBuffer(data string) Buffer {
if len(data) == 0 {
return nilBuffer
}
var (
idx = 0
buf8 = make([]byte, 0, len(data))
buf16 []uint16
buf32 []rune
)
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if r < utf8.RuneSelf {
buf8 = append(buf8, byte(r))
continue
}
if r <= 0xffff {
buf16 = make([]uint16, len(buf8), len(data))
for i, v := range buf8 {
buf16[i] = uint16(v)
}
buf8 = nil
buf16 = append(buf16, uint16(r))
goto copy16
}
buf32 = make([]rune, len(buf8), len(data))
for i, v := range buf8 {
buf32[i] = rune(uint32(v))
}
buf8 = nil
buf32 = append(buf32, r)
goto copy32
}
return &asciiBuffer{
arr: buf8,
}
copy16:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if r <= 0xffff {
buf16 = append(buf16, uint16(r))
continue
}
buf32 = make([]rune, len(buf16), len(data))
for i, v := range buf16 {
buf32[i] = rune(uint32(v))
}
buf16 = nil
buf32 = append(buf32, r)
goto copy32
}
return &basicBuffer{
arr: buf16,
}
copy32:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
buf32 = append(buf32, r)
}
return &supplementalBuffer{
arr: buf32,
}
}

186
vendor/github.com/google/cel-go/common/source.go generated vendored Normal file
View File

@ -0,0 +1,186 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
import (
"strings"
"unicode/utf8"
"github.com/google/cel-go/common/runes"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Source interface for filter source contents.
type Source interface {
// Content returns the source content represented as a string.
// Examples contents are the single file contents, textbox field,
// or url parameter.
Content() string
// Description gives a brief description of the source.
// Example descriptions are a file name or ui element.
Description() string
// LineOffsets gives the character offsets at which lines occur.
// The zero-th entry should refer to the break between the first
// and second line, or EOF if there is only one line of source.
LineOffsets() []int32
// LocationOffset translates a Location to an offset.
// Given the line and column of the Location returns the
// Location's character offset in the Source, and a bool
// indicating whether the Location was found.
LocationOffset(location Location) (int32, bool)
// OffsetLocation translates a character offset to a Location, or
// false if the conversion was not feasible.
OffsetLocation(offset int32) (Location, bool)
// NewLocation takes an input line and column and produces a Location.
// The default behavior is to treat the line and column as absolute,
// but concrete derivations may use this method to convert a relative
// line and column position into an absolute location.
NewLocation(line, col int) Location
// Snippet returns a line of content and whether the line was found.
Snippet(line int) (string, bool)
}
// The sourceImpl type implementation of the Source interface.
type sourceImpl struct {
runes.Buffer
description string
lineOffsets []int32
idOffsets map[int64]int32
}
var _ runes.Buffer = &sourceImpl{}
// TODO(jimlarson) "Character offsets" should index the code points
// within the UTF-8 encoded string. It currently indexes bytes.
// Can be accomplished by using rune[] instead of string for contents.
// NewTextSource creates a new Source from the input text string.
func NewTextSource(text string) Source {
return NewStringSource(text, "<input>")
}
// NewStringSource creates a new Source from the given contents and description.
func NewStringSource(contents string, description string) Source {
// Compute line offsets up front as they are referred to frequently.
lines := strings.Split(contents, "\n")
offsets := make([]int32, len(lines))
var offset int32
for i, line := range lines {
offset = offset + int32(utf8.RuneCountInString(line)) + 1
offsets[int32(i)] = offset
}
return &sourceImpl{
Buffer: runes.NewBuffer(contents),
description: description,
lineOffsets: offsets,
idOffsets: map[int64]int32{},
}
}
// NewInfoSource creates a new Source from a SourceInfo.
func NewInfoSource(info *exprpb.SourceInfo) Source {
return &sourceImpl{
Buffer: runes.NewBuffer(""),
description: info.GetLocation(),
lineOffsets: info.GetLineOffsets(),
idOffsets: info.GetPositions(),
}
}
// Content implements the Source interface method.
func (s *sourceImpl) Content() string {
return s.Slice(0, s.Len())
}
// Description implements the Source interface method.
func (s *sourceImpl) Description() string {
return s.description
}
// LineOffsets implements the Source interface method.
func (s *sourceImpl) LineOffsets() []int32 {
return s.lineOffsets
}
// LocationOffset implements the Source interface method.
func (s *sourceImpl) LocationOffset(location Location) (int32, bool) {
if lineOffset, found := s.findLineOffset(location.Line()); found {
return lineOffset + int32(location.Column()), true
}
return -1, false
}
// NewLocation implements the Source interface method.
func (s *sourceImpl) NewLocation(line, col int) Location {
return NewLocation(line, col)
}
// OffsetLocation implements the Source interface method.
func (s *sourceImpl) OffsetLocation(offset int32) (Location, bool) {
line, lineOffset := s.findLine(offset)
return NewLocation(int(line), int(offset-lineOffset)), true
}
// Snippet implements the Source interface method.
func (s *sourceImpl) Snippet(line int) (string, bool) {
charStart, found := s.findLineOffset(line)
if !found || s.Len() == 0 {
return "", false
}
charEnd, found := s.findLineOffset(line + 1)
if found {
return s.Slice(int(charStart), int(charEnd-1)), true
}
return s.Slice(int(charStart), s.Len()), true
}
// findLineOffset returns the offset where the (1-indexed) line begins,
// or false if line doesn't exist.
func (s *sourceImpl) findLineOffset(line int) (int32, bool) {
if line == 1 {
return 0, true
}
if line > 1 && line <= int(len(s.lineOffsets)) {
offset := s.lineOffsets[line-2]
return offset, true
}
return -1, false
}
// findLine finds the line that contains the given character offset and
// returns the line number and offset of the beginning of that line.
// Note that the last line is treated as if it contains all offsets
// beyond the end of the actual source.
func (s *sourceImpl) findLine(characterOffset int32) (int32, int32) {
var line int32 = 1
for _, lineOffset := range s.lineOffsets {
if lineOffset > characterOffset {
break
} else {
line++
}
}
if line == 1 {
return line, 0
}
return line, s.lineOffsets[line-2]
}

View File

@ -0,0 +1,89 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"any_value.go",
"bool.go",
"bytes.go",
"compare.go",
"double.go",
"duration.go",
"err.go",
"int.go",
"iterator.go",
"json_value.go",
"list.go",
"map.go",
"null.go",
"object.go",
"overflow.go",
"provider.go",
"string.go",
"timestamp.go",
"type.go",
"uint.go",
"unknown.go",
"util.go",
],
importpath = "github.com/google/cel-go/common/types",
deps = [
"//common/overloads:go_default_library",
"//common/types/pb:go_default_library",
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"@com_github_stoewer_go_strcase//:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_genproto//googleapis/rpc/status:go_default_library",
"@org_golang_google_grpc//codes:go_default_library",
"@org_golang_google_grpc//status:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"bool_test.go",
"bytes_test.go",
"double_test.go",
"duration_test.go",
"int_test.go",
"json_list_test.go",
"json_struct_test.go",
"list_test.go",
"map_test.go",
"null_test.go",
"object_test.go",
"provider_test.go",
"string_test.go",
"timestamp_test.go",
"type_test.go",
"uint_test.go",
"util_test.go",
],
embed = [":go_default_library"],
deps = [
"//common/types/ref:go_default_library",
"//test:go_default_library",
"//test/proto3pb:test_all_types_go_proto",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
],
)

View File

@ -0,0 +1,24 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"reflect"
anypb "google.golang.org/protobuf/types/known/anypb"
)
// anyValueType constant representing the reflected type of google.protobuf.Any.
var anyValueType = reflect.TypeOf(&anypb.Any{})

142
vendor/github.com/google/cel-go/common/types/bool.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"strconv"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Bool type that implements ref.Val and supports comparison and negation.
type Bool bool
var (
// BoolType singleton.
BoolType = NewTypeValue("bool",
traits.ComparerType,
traits.NegatorType)
// boolWrapperType golang reflected type for protobuf bool wrapper type.
boolWrapperType = reflect.TypeOf(&wrapperspb.BoolValue{})
)
// Boolean constants
const (
False = Bool(false)
True = Bool(true)
)
// Compare implements the traits.Comparer interface method.
func (b Bool) Compare(other ref.Val) ref.Val {
otherBool, ok := other.(Bool)
if !ok {
return ValOrErr(other, "no such overload")
}
if b == otherBool {
return IntZero
}
if !b && otherBool {
return IntNegOne
}
return IntOne
}
// ConvertToNative implements the ref.Val interface method.
func (b Bool) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Bool:
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped to a wrapperspb.BoolValue before being packed into an Any.
return anypb.New(wrapperspb.Bool(bool(b)))
case boolWrapperType:
// Convert the bool to a wrapperspb.BoolValue.
return wrapperspb.Bool(bool(b)), nil
case jsonValueType:
// Return the bool as a new structpb.Value.
return structpb.NewBoolValue(bool(b)), nil
default:
if typeDesc.Elem().Kind() == reflect.Bool {
p := bool(b)
return &p, nil
}
}
case reflect.Interface:
bv := b.Value()
if reflect.TypeOf(bv).Implements(typeDesc) {
return bv, nil
}
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from bool to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (b Bool) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String(strconv.FormatBool(bool(b)))
case BoolType:
return b
case TypeType:
return BoolType
}
return NewErr("type conversion error from '%v' to '%v'", BoolType, typeVal)
}
// Equal implements the ref.Val interface method.
func (b Bool) Equal(other ref.Val) ref.Val {
otherBool, ok := other.(Bool)
return Bool(ok && b == otherBool)
}
// Negate implements the traits.Negater interface method.
func (b Bool) Negate() ref.Val {
return !b
}
// Type implements the ref.Val interface method.
func (b Bool) Type() ref.Type {
return BoolType
}
// Value implements the ref.Val interface method.
func (b Bool) Value() interface{} {
return bool(b)
}
// IsBool returns whether the input ref.Val or ref.Type is equal to BoolType.
func IsBool(elem ref.Val) bool {
switch v := elem.(type) {
case Bool:
return true
case ref.Val:
return v.Type() == BoolType
default:
return false
}
}

132
vendor/github.com/google/cel-go/common/types/bytes.go generated vendored Normal file
View File

@ -0,0 +1,132 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"bytes"
"encoding/base64"
"fmt"
"reflect"
"unicode/utf8"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Bytes type that implements ref.Val and supports add, compare, and size
// operations.
type Bytes []byte
var (
// BytesType singleton.
BytesType = NewTypeValue("bytes",
traits.AdderType,
traits.ComparerType,
traits.SizerType)
// byteWrapperType golang reflected type for protobuf bytes wrapper type.
byteWrapperType = reflect.TypeOf(&wrapperspb.BytesValue{})
)
// Add implements traits.Adder interface method by concatenating byte sequences.
func (b Bytes) Add(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
if !ok {
return ValOrErr(other, "no such overload")
}
return append(b, otherBytes...)
}
// Compare implements traits.Comparer interface method by lexicographic ordering.
func (b Bytes) Compare(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
if !ok {
return ValOrErr(other, "no such overload")
}
return Int(bytes.Compare(b, otherBytes))
}
// ConvertToNative implements the ref.Val interface method.
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Array, reflect.Slice:
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Bytes([]byte(b)))
case byteWrapperType:
// Convert the bytes to a wrapperspb.BytesValue.
return wrapperspb.Bytes([]byte(b)), nil
case jsonValueType:
// CEL follows the proto3 to JSON conversion by encoding bytes to a string via base64.
// The encoding below matches the golang 'encoding/json' behavior during marshaling,
// which uses base64.StdEncoding.
str := base64.StdEncoding.EncodeToString([]byte(b))
return structpb.NewStringValue(str), nil
}
case reflect.Interface:
bv := b.Value()
if reflect.TypeOf(bv).Implements(typeDesc) {
return bv, nil
}
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from Bytes to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (b Bytes) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
if !utf8.Valid(b) {
return NewErr("invalid UTF-8 in bytes, cannot convert to string")
}
return String(b)
case BytesType:
return b
case TypeType:
return BytesType
}
return NewErr("type conversion error from '%s' to '%s'", BytesType, typeVal)
}
// Equal implements the ref.Val interface method.
func (b Bytes) Equal(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
return Bool(ok && bytes.Equal(b, otherBytes))
}
// Size implements the traits.Sizer interface method.
func (b Bytes) Size() ref.Val {
return Int(len(b))
}
// Type implements the ref.Val interface method.
func (b Bytes) Type() ref.Type {
return BytesType
}
// Value implements the ref.Val interface method.
func (b Bytes) Value() interface{} {
return []byte(b)
}

View File

@ -0,0 +1,97 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"math"
"github.com/google/cel-go/common/types/ref"
)
func compareDoubleInt(d Double, i Int) Int {
if d < math.MinInt64 {
return IntNegOne
}
if d > math.MaxInt64 {
return IntOne
}
return compareDouble(d, Double(i))
}
func compareIntDouble(i Int, d Double) Int {
return -compareDoubleInt(d, i)
}
func compareDoubleUint(d Double, u Uint) Int {
if d < 0 {
return IntNegOne
}
if d > math.MaxUint64 {
return IntOne
}
return compareDouble(d, Double(u))
}
func compareUintDouble(u Uint, d Double) Int {
return -compareDoubleUint(d, u)
}
func compareIntUint(i Int, u Uint) Int {
if i < 0 || u > math.MaxInt64 {
return IntNegOne
}
cmp := i - Int(u)
if cmp < 0 {
return IntNegOne
}
if cmp > 0 {
return IntOne
}
return IntZero
}
func compareUintInt(u Uint, i Int) Int {
return -compareIntUint(i, u)
}
func compareDouble(a, b Double) Int {
if a < b {
return IntNegOne
}
if a > b {
return IntOne
}
return IntZero
}
func compareInt(a, b Int) ref.Val {
if a < b {
return IntNegOne
}
if a > b {
return IntOne
}
return IntZero
}
func compareUint(a, b Uint) ref.Val {
if a < b {
return IntNegOne
}
if a > b {
return IntOne
}
return IntZero
}

17
vendor/github.com/google/cel-go/common/types/doc.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package types contains the types, traits, and utilities common to all
// components of expression handling.
package types

216
vendor/github.com/google/cel-go/common/types/double.go generated vendored Normal file
View File

@ -0,0 +1,216 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"math"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Double type that implements ref.Val, comparison, and mathematical
// operations.
type Double float64
var (
// DoubleType singleton.
DoubleType = NewTypeValue("double",
traits.AdderType,
traits.ComparerType,
traits.DividerType,
traits.MultiplierType,
traits.NegatorType,
traits.SubtractorType)
// doubleWrapperType reflected type for protobuf double wrapper type.
doubleWrapperType = reflect.TypeOf(&wrapperspb.DoubleValue{})
// floatWrapperType reflected type for protobuf float wrapper type.
floatWrapperType = reflect.TypeOf(&wrapperspb.FloatValue{})
)
// Add implements traits.Adder.Add.
func (d Double) Add(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d + otherDouble
}
// Compare implements traits.Comparer.Compare.
func (d Double) Compare(other ref.Val) ref.Val {
if math.IsNaN(float64(d)) {
return NewErr("NaN values cannot be ordered")
}
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return NewErr("NaN values cannot be ordered")
}
return compareDouble(d, ov)
case Int:
return compareDoubleInt(d, ov)
case Uint:
return compareDoubleUint(d, ov)
default:
return MaybeNoSuchOverloadErr(other)
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Float32:
v := float32(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Float64:
v := float64(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Double(float64(d)))
case doubleWrapperType:
// Convert to a wrapperspb.DoubleValue
return wrapperspb.Double(float64(d)), nil
case floatWrapperType:
// Convert to a wrapperspb.FloatValue (with truncation).
return wrapperspb.Float(float32(d)), nil
case jsonValueType:
// Note, there are special cases for proto3 to json conversion that
// expect the floating point value to be converted to a NaN,
// Infinity, or -Infinity string values, but the jsonpb string
// marshaling of the protobuf.Value will handle this conversion.
return structpb.NewNumberValue(float64(d)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Float32:
v := float32(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Float64:
v := float64(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
dv := d.Value()
if reflect.TypeOf(dv).Implements(typeDesc) {
return dv, nil
}
if reflect.TypeOf(d).Implements(typeDesc) {
return d, nil
}
}
return nil, fmt.Errorf("type conversion error from Double to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (d Double) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
i, err := doubleToInt64Checked(float64(d))
if err != nil {
return wrapErr(err)
}
return Int(i)
case UintType:
i, err := doubleToUint64Checked(float64(d))
if err != nil {
return wrapErr(err)
}
return Uint(i)
case DoubleType:
return d
case StringType:
return String(fmt.Sprintf("%g", float64(d)))
case TypeType:
return DoubleType
}
return NewErr("type conversion error from '%s' to '%s'", DoubleType, typeVal)
}
// Divide implements traits.Divider.Divide.
func (d Double) Divide(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d / otherDouble
}
// Equal implements ref.Val.Equal.
func (d Double) Equal(other ref.Val) ref.Val {
if math.IsNaN(float64(d)) {
return False
}
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return False
}
return Bool(d == ov)
case Int:
return Bool(compareDoubleInt(d, ov) == 0)
case Uint:
return Bool(compareDoubleUint(d, ov) == 0)
default:
return False
}
}
// Multiply implements traits.Multiplier.Multiply.
func (d Double) Multiply(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d * otherDouble
}
// Negate implements traits.Negater.Negate.
func (d Double) Negate() ref.Val {
return -d
}
// Subtract implements traits.Subtractor.Subtract.
func (d Double) Subtract(subtrahend ref.Val) ref.Val {
subtraDouble, ok := subtrahend.(Double)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
return d - subtraDouble
}
// Type implements ref.Val.Type.
func (d Double) Type() ref.Type {
return DoubleType
}
// Value implements ref.Val.Value.
func (d Double) Value() interface{} {
return float64(d)
}

View File

@ -0,0 +1,199 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"strconv"
"time"
"github.com/google/cel-go/common/overloads"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
dpb "google.golang.org/protobuf/types/known/durationpb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// Duration type that implements ref.Val and supports add, compare, negate,
// and subtract operators. This type is also a receiver which means it can
// participate in dispatch to receiver functions.
type Duration struct {
time.Duration
}
func durationOf(d time.Duration) Duration {
return Duration{Duration: d}
}
var (
// DurationType singleton.
DurationType = NewTypeValue("google.protobuf.Duration",
traits.AdderType,
traits.ComparerType,
traits.NegatorType,
traits.ReceiverType,
traits.SubtractorType)
)
// Add implements traits.Adder.Add.
func (d Duration) Add(other ref.Val) ref.Val {
switch other.Type() {
case DurationType:
dur2 := other.(Duration)
val, err := addDurationChecked(d.Duration, dur2.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
case TimestampType:
ts := other.(Timestamp).Time
val, err := addTimeDurationChecked(ts, d.Duration)
if err != nil {
return wrapErr(err)
}
return timestampOf(val)
}
return MaybeNoSuchOverloadErr(other)
}
// Compare implements traits.Comparer.Compare.
func (d Duration) Compare(other ref.Val) ref.Val {
otherDur, ok := other.(Duration)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
d1 := d.Duration
d2 := otherDur.Duration
switch {
case d1 < d2:
return IntNegOne
case d1 > d2:
return IntOne
default:
return IntZero
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (d Duration) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the duration is already assignable to the desired type return it.
if reflect.TypeOf(d.Duration).AssignableTo(typeDesc) {
return d.Duration, nil
}
if reflect.TypeOf(d).AssignableTo(typeDesc) {
return d, nil
}
switch typeDesc {
case anyValueType:
// Pack the duration as a dpb.Duration into an Any value.
return anypb.New(dpb.New(d.Duration))
case durationValueType:
// Unwrap the CEL value to its underlying proto value.
return dpb.New(d.Duration), nil
case jsonValueType:
// CEL follows the proto3 to JSON conversion.
// Note, using jsonpb would wrap the result in extra double quotes.
v := d.ConvertToType(StringType)
if IsError(v) {
return nil, v.(*Err)
}
return structpb.NewStringValue(string(v.(String))), nil
}
return nil, fmt.Errorf("type conversion error from 'Duration' to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (d Duration) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String(strconv.FormatFloat(d.Seconds(), 'f', -1, 64) + "s")
case IntType:
return Int(d.Duration)
case DurationType:
return d
case TypeType:
return DurationType
}
return NewErr("type conversion error from '%s' to '%s'", DurationType, typeVal)
}
// Equal implements ref.Val.Equal.
func (d Duration) Equal(other ref.Val) ref.Val {
otherDur, ok := other.(Duration)
return Bool(ok && d.Duration == otherDur.Duration)
}
// Negate implements traits.Negater.Negate.
func (d Duration) Negate() ref.Val {
val, err := negateDurationChecked(d.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
}
// Receive implements traits.Receiver.Receive.
func (d Duration) Receive(function string, overload string, args []ref.Val) ref.Val {
if len(args) == 0 {
if f, found := durationZeroArgOverloads[function]; found {
return f(d.Duration)
}
}
return NoSuchOverloadErr()
}
// Subtract implements traits.Subtractor.Subtract.
func (d Duration) Subtract(subtrahend ref.Val) ref.Val {
subtraDur, ok := subtrahend.(Duration)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
val, err := subtractDurationChecked(d.Duration, subtraDur.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
}
// Type implements ref.Val.Type.
func (d Duration) Type() ref.Type {
return DurationType
}
// Value implements ref.Val.Value.
func (d Duration) Value() interface{} {
return d.Duration
}
var (
durationValueType = reflect.TypeOf(&dpb.Duration{})
durationZeroArgOverloads = map[string]func(time.Duration) ref.Val{
overloads.TimeGetHours: func(dur time.Duration) ref.Val {
return Int(dur.Hours())
},
overloads.TimeGetMinutes: func(dur time.Duration) ref.Val {
return Int(dur.Minutes())
},
overloads.TimeGetSeconds: func(dur time.Duration) ref.Val {
return Int(dur.Seconds())
},
overloads.TimeGetMilliseconds: func(dur time.Duration) ref.Val {
return Int(dur.Milliseconds())
}}
)

130
vendor/github.com/google/cel-go/common/types/err.go generated vendored Normal file
View File

@ -0,0 +1,130 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"errors"
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
)
// Err type which extends the built-in go error and implements ref.Val.
type Err struct {
error
}
var (
// ErrType singleton.
ErrType = NewTypeValue("error")
// errDivideByZero is an error indicating a division by zero of an integer value.
errDivideByZero = errors.New("division by zero")
// errModulusByZero is an error indicating a modulus by zero of an integer value.
errModulusByZero = errors.New("modulus by zero")
// errIntOverflow is an error representing integer overflow.
errIntOverflow = errors.New("integer overflow")
// errUintOverflow is an error representing unsigned integer overflow.
errUintOverflow = errors.New("unsigned integer overflow")
// errDurationOverflow is an error representing duration overflow.
errDurationOverflow = errors.New("duration overflow")
// errTimestampOverflow is an error representing timestamp overflow.
errTimestampOverflow = errors.New("timestamp overflow")
celErrTimestampOverflow = &Err{error: errTimestampOverflow}
// celErrNoSuchOverload indicates that the call arguments did not match a supported method signature.
celErrNoSuchOverload = NewErr("no such overload")
)
// NewErr creates a new Err described by the format string and args.
// TODO: Audit the use of this function and standardize the error messages and codes.
func NewErr(format string, args ...interface{}) ref.Val {
return &Err{fmt.Errorf(format, args...)}
}
// NoSuchOverloadErr returns a new types.Err instance with a no such overload message.
func NoSuchOverloadErr() ref.Val {
return celErrNoSuchOverload
}
// UnsupportedRefValConversionErr returns a types.NewErr instance with a no such conversion
// message that indicates that the native value could not be converted to a CEL ref.Val.
func UnsupportedRefValConversionErr(val interface{}) ref.Val {
return NewErr("unsupported conversion to ref.Val: (%T)%v", val, val)
}
// MaybeNoSuchOverloadErr returns the error or unknown if the input ref.Val is one of these types,
// else a new no such overload error.
func MaybeNoSuchOverloadErr(val ref.Val) ref.Val {
return ValOrErr(val, "no such overload")
}
// ValOrErr either returns the existing error or creates a new one.
// TODO: Audit the use of this function and standardize the error messages and codes.
func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val {
if val == nil || !IsUnknownOrError(val) {
return NewErr(format, args...)
}
return val
}
// wrapErr wraps an existing Go error value into a CEL Err value.
func wrapErr(err error) ref.Val {
return &Err{error: err}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (e *Err) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
return nil, e.error
}
// ConvertToType implements ref.Val.ConvertToType.
func (e *Err) ConvertToType(typeVal ref.Type) ref.Val {
// Errors are not convertible to other representations.
return e
}
// Equal implements ref.Val.Equal.
func (e *Err) Equal(other ref.Val) ref.Val {
// An error cannot be equal to any other value, so it returns itself.
return e
}
// String implements fmt.Stringer.
func (e *Err) String() string {
return e.error.Error()
}
// Type implements ref.Val.Type.
func (e *Err) Type() ref.Type {
return ErrType
}
// Value implements ref.Val.Value.
func (e *Err) Value() interface{} {
return e.error
}
// IsError returns whether the input element ref.Type or ref.Val is equal to
// the ErrType singleton.
func IsError(val ref.Val) bool {
switch val.(type) {
case *Err:
return true
default:
return false
}
}

297
vendor/github.com/google/cel-go/common/types/int.go generated vendored Normal file
View File

@ -0,0 +1,297 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"math"
"reflect"
"strconv"
"time"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Int type that implements ref.Val as well as comparison and math operators.
type Int int64
// Int constants used for comparison results.
const (
// IntZero is the zero-value for Int
IntZero = Int(0)
IntOne = Int(1)
IntNegOne = Int(-1)
)
var (
// IntType singleton.
IntType = NewTypeValue("int",
traits.AdderType,
traits.ComparerType,
traits.DividerType,
traits.ModderType,
traits.MultiplierType,
traits.NegatorType,
traits.SubtractorType)
// int32WrapperType reflected type for protobuf int32 wrapper type.
int32WrapperType = reflect.TypeOf(&wrapperspb.Int32Value{})
// int64WrapperType reflected type for protobuf int64 wrapper type.
int64WrapperType = reflect.TypeOf(&wrapperspb.Int64Value{})
)
// Add implements traits.Adder.Add.
func (i Int) Add(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := addInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Compare implements traits.Comparer.Compare.
func (i Int) Compare(other ref.Val) ref.Val {
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return NewErr("NaN values cannot be ordered")
}
return compareIntDouble(i, ov)
case Int:
return compareInt(i, ov)
case Uint:
return compareIntUint(i, ov)
default:
return MaybeNoSuchOverloadErr(other)
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Int, reflect.Int32:
// Enums are also mapped as int32 derivations.
// Note, the code doesn't convert to the enum value directly since this is not known, but
// the net effect with respect to proto-assignment is handled correctly by the reflection
// Convert method.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Int64:
return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Int64(int64(i)))
case int32WrapperType:
// Convert the value to a wrapperspb.Int32Value, error on overflow.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
return wrapperspb.Int32(v), nil
case int64WrapperType:
// Convert the value to a wrapperspb.Int64Value.
return wrapperspb.Int64(int64(i)), nil
case jsonValueType:
// The proto-to-JSON conversion rules would convert all 64-bit integer values to JSON
// decimal strings. Because CEL ints might come from the automatic widening of 32-bit
// values in protos, the JSON type is chosen dynamically based on the value.
//
// - Integers -2^53-1 < n < 2^53-1 are encoded as JSON numbers.
// - Integers outside this range are encoded as JSON strings.
//
// The integer to float range represents the largest interval where such a conversion
// can round-trip accurately. Thus, conversions from a 32-bit source can expect a JSON
// number as with protobuf. Those consuming JSON from a 64-bit source must be able to
// handle either a JSON number or a JSON decimal string. To handle these cases safely
// the string values must be explicitly converted to int() within a CEL expression;
// however, it is best to simply stay within the JSON number range when building JSON
// objects in CEL.
if i.isJSONSafe() {
return structpb.NewNumberValue(float64(i)), nil
}
// Proto3 to JSON conversion requires string-formatted int64 values
// since the conversion to floating point would result in truncation.
return structpb.NewStringValue(strconv.FormatInt(int64(i), 10)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Int32:
// Convert the value to a wrapperspb.Int32Value, error on overflow.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Int64:
v := int64(i)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
iv := i.Value()
if reflect.TypeOf(iv).Implements(typeDesc) {
return iv, nil
}
if reflect.TypeOf(i).Implements(typeDesc) {
return i, nil
}
}
return nil, fmt.Errorf("unsupported type conversion from 'int' to %v", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (i Int) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
return i
case UintType:
u, err := int64ToUint64Checked(int64(i))
if err != nil {
return wrapErr(err)
}
return Uint(u)
case DoubleType:
return Double(i)
case StringType:
return String(fmt.Sprintf("%d", int64(i)))
case TimestampType:
// The maximum positive value that can be passed to time.Unix is math.MaxInt64 minus the number
// of seconds between year 1 and year 1970. See comments on unixToInternal.
if int64(i) < minUnixTime || int64(i) > maxUnixTime {
return celErrTimestampOverflow
}
return timestampOf(time.Unix(int64(i), 0).UTC())
case TypeType:
return IntType
}
return NewErr("type conversion error from '%s' to '%s'", IntType, typeVal)
}
// Divide implements traits.Divider.Divide.
func (i Int) Divide(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := divideInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Equal implements ref.Val.Equal.
func (i Int) Equal(other ref.Val) ref.Val {
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return False
}
return Bool(compareIntDouble(i, ov) == 0)
case Int:
return Bool(i == ov)
case Uint:
return Bool(compareIntUint(i, ov) == 0)
default:
return False
}
}
// Modulo implements traits.Modder.Modulo.
func (i Int) Modulo(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := moduloInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Multiply implements traits.Multiplier.Multiply.
func (i Int) Multiply(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := multiplyInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Negate implements traits.Negater.Negate.
func (i Int) Negate() ref.Val {
val, err := negateInt64Checked(int64(i))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Subtract implements traits.Subtractor.Subtract.
func (i Int) Subtract(subtrahend ref.Val) ref.Val {
subtraInt, ok := subtrahend.(Int)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
val, err := subtractInt64Checked(int64(i), int64(subtraInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Type implements ref.Val.Type.
func (i Int) Type() ref.Type {
return IntType
}
// Value implements ref.Val.Value.
func (i Int) Value() interface{} {
return int64(i)
}
// isJSONSafe indicates whether the int is safely representable as a floating point value in JSON.
func (i Int) isJSONSafe() bool {
return i >= minIntJSON && i <= maxIntJSON
}
const (
// maxIntJSON is defined as the Number.MAX_SAFE_INTEGER value per EcmaScript 6.
maxIntJSON = 1<<53 - 1
// minIntJSON is defined as the Number.MIN_SAFE_INTEGER value per EcmaScript 6.
minIntJSON = -maxIntJSON
)

View File

@ -0,0 +1,55 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var (
// IteratorType singleton.
IteratorType = NewTypeValue("iterator", traits.IteratorType)
)
// baseIterator is the basis for list, map, and object iterators.
//
// An iterator in and of itself should not be a valid value for comparison, but must implement the
// `ref.Val` methods in order to be well-supported within instruction arguments processed by the
// interpreter.
type baseIterator struct{}
func (*baseIterator) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
return nil, fmt.Errorf("type conversion on iterators not supported")
}
func (*baseIterator) ConvertToType(typeVal ref.Type) ref.Val {
return NewErr("no such overload")
}
func (*baseIterator) Equal(other ref.Val) ref.Val {
return NewErr("no such overload")
}
func (*baseIterator) Type() ref.Type {
return IteratorType
}
func (*baseIterator) Value() interface{} {
return nil
}

View File

@ -0,0 +1,28 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"reflect"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// JSON type constants representing the reflected types of protobuf JSON values.
var (
jsonValueType = reflect.TypeOf(&structpb.Value{})
jsonListValueType = reflect.TypeOf(&structpb.ListValue{})
jsonStructType = reflect.TypeOf(&structpb.Struct{})
)

489
vendor/github.com/google/cel-go/common/types/list.go generated vendored Normal file
View File

@ -0,0 +1,489 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
var (
// ListType singleton.
ListType = NewTypeValue("list",
traits.AdderType,
traits.ContainerType,
traits.IndexerType,
traits.IterableType,
traits.SizerType)
)
// NewDynamicList returns a traits.Lister with heterogenous elements.
// value should be an array of "native" types, i.e. any type that
// NativeToValue() can convert to a ref.Val.
func NewDynamicList(adapter ref.TypeAdapter, value interface{}) traits.Lister {
refValue := reflect.ValueOf(value)
return &baseList{
TypeAdapter: adapter,
value: value,
size: refValue.Len(),
get: func(i int) interface{} {
return refValue.Index(i).Interface()
},
}
}
// NewStringList returns a traits.Lister containing only strings.
func NewStringList(adapter ref.TypeAdapter, elems []string) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: elems,
size: len(elems),
get: func(i int) interface{} { return elems[i] },
}
}
// NewRefValList returns a traits.Lister with ref.Val elements.
//
// This type specialization is used with list literals within CEL expressions.
func NewRefValList(adapter ref.TypeAdapter, elems []ref.Val) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: elems,
size: len(elems),
get: func(i int) interface{} { return elems[i] },
}
}
// NewProtoList returns a traits.Lister based on a pb.List instance.
func NewProtoList(adapter ref.TypeAdapter, list protoreflect.List) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: list,
size: list.Len(),
get: func(i int) interface{} { return list.Get(i).Interface() },
}
}
// NewJSONList returns a traits.Lister based on structpb.ListValue instance.
func NewJSONList(adapter ref.TypeAdapter, l *structpb.ListValue) traits.Lister {
vals := l.GetValues()
return &baseList{
TypeAdapter: adapter,
value: l,
size: len(vals),
get: func(i int) interface{} { return vals[i] },
}
}
// NewMutableList creates a new mutable list whose internal state can be modified.
func NewMutableList(adapter ref.TypeAdapter) traits.MutableLister {
var mutableValues []ref.Val
return &mutableList{
baseList: &baseList{
TypeAdapter: adapter,
value: mutableValues,
size: 0,
get: func(i int) interface{} { return mutableValues[i] },
},
mutableValues: mutableValues,
}
}
// baseList points to a list containing elements of any type.
// The `value` is an array of native values, and refValue is its reflection object.
// The `ref.TypeAdapter` enables native type to CEL type conversions.
type baseList struct {
ref.TypeAdapter
value interface{}
// size indicates the number of elements within the list.
// Since objects are immutable the size of a list is static.
size int
// get returns a value at the specified integer index.
// The index is guaranteed to be checked against the list index range.
get func(int) interface{}
}
// Add implements the traits.Adder interface method.
func (l *baseList) Add(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() == IntZero {
return other
}
if otherList.Size() == IntZero {
return l
}
return &concatList{
TypeAdapter: l.TypeAdapter,
prevList: l,
nextList: otherList}
}
// Contains implements the traits.Container interface method.
func (l *baseList) Contains(elem ref.Val) ref.Val {
for i := 0; i < l.size; i++ {
val := l.NativeToValue(l.get(i))
cmp := elem.Equal(val)
b, ok := cmp.(Bool)
if ok && b == True {
return True
}
}
return False
}
// ConvertToNative implements the ref.Val interface method.
func (l *baseList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the underlying list value is assignable to the reflected type return it.
if reflect.TypeOf(l.value).AssignableTo(typeDesc) {
return l.value, nil
}
// If the list wrapper is assignable to the desired type return it.
if reflect.TypeOf(l).AssignableTo(typeDesc) {
return l, nil
}
// Attempt to convert the list to a set of well known protobuf types.
switch typeDesc {
case anyValueType:
json, err := l.ConvertToNative(jsonListValueType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonListValueType:
jsonValues, err :=
l.ConvertToNative(reflect.TypeOf([]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonList := &structpb.ListValue{Values: jsonValues.([]*structpb.Value)}
if typeDesc == jsonListValueType {
return jsonList, nil
}
return structpb.NewListValue(jsonList), nil
}
// Non-list conversion.
if typeDesc.Kind() != reflect.Slice && typeDesc.Kind() != reflect.Array {
return nil, fmt.Errorf("type conversion error from list to '%v'", typeDesc)
}
// List conversion.
// Allow the element ConvertToNative() function to determine whether conversion is possible.
otherElemType := typeDesc.Elem()
elemCount := l.size
nativeList := reflect.MakeSlice(typeDesc, elemCount, elemCount)
for i := 0; i < elemCount; i++ {
elem := l.NativeToValue(l.get(i))
nativeElemVal, err := elem.ConvertToNative(otherElemType)
if err != nil {
return nil, err
}
nativeList.Index(i).Set(reflect.ValueOf(nativeElemVal))
}
return nativeList.Interface(), nil
}
// ConvertToType implements the ref.Val interface method.
func (l *baseList) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case ListType:
return l
case TypeType:
return ListType
}
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
}
// Equal implements the ref.Val interface method.
func (l *baseList) Equal(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return False
}
if l.Size() != otherList.Size() {
return False
}
for i := IntZero; i < l.Size().(Int); i++ {
thisElem := l.Get(i)
otherElem := otherList.Get(i)
elemEq := Equal(thisElem, otherElem)
if elemEq == False {
return False
}
}
return True
}
// Get implements the traits.Indexer interface method.
func (l *baseList) Get(index ref.Val) ref.Val {
ind, err := indexOrError(index)
if err != nil {
return ValOrErr(index, err.Error())
}
if ind < 0 || ind >= l.size {
return NewErr("index '%d' out of range in list size '%d'", ind, l.Size())
}
return l.NativeToValue(l.get(ind))
}
// Iterator implements the traits.Iterable interface method.
func (l *baseList) Iterator() traits.Iterator {
return newListIterator(l)
}
// Size implements the traits.Sizer interface method.
func (l *baseList) Size() ref.Val {
return Int(l.size)
}
// Type implements the ref.Val interface method.
func (l *baseList) Type() ref.Type {
return ListType
}
// Value implements the ref.Val interface method.
func (l *baseList) Value() interface{} {
return l.value
}
// mutableList aggregates values into its internal storage. For use with internal CEL variables only.
type mutableList struct {
*baseList
mutableValues []ref.Val
}
// Add copies elements from the other list into the internal storage of the mutable list.
// The ref.Val returned by Add is the receiver.
func (l *mutableList) Add(other ref.Val) ref.Val {
switch otherList := other.(type) {
case *mutableList:
l.mutableValues = append(l.mutableValues, otherList.mutableValues...)
l.size += len(otherList.mutableValues)
case traits.Lister:
for i := IntZero; i < otherList.Size().(Int); i++ {
l.size++
l.mutableValues = append(l.mutableValues, otherList.Get(i))
}
default:
return MaybeNoSuchOverloadErr(otherList)
}
return l
}
// ToImmutableList returns an immutable list based on the internal storage of the mutable list.
func (l *mutableList) ToImmutableList() traits.Lister {
// The reference to internal state is guaranteed to be safe as this call is only performed
// when mutations have been completed.
return NewRefValList(l.TypeAdapter, l.mutableValues)
}
// concatList combines two list implementations together into a view.
// The `ref.TypeAdapter` enables native type to CEL type conversions.
type concatList struct {
ref.TypeAdapter
value interface{}
prevList traits.Lister
nextList traits.Lister
}
// Add implements the traits.Adder interface method.
func (l *concatList) Add(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() == IntZero {
return other
}
if otherList.Size() == IntZero {
return l
}
return &concatList{
TypeAdapter: l.TypeAdapter,
prevList: l,
nextList: otherList}
}
// Contains implements the traits.Container interface method.
func (l *concatList) Contains(elem ref.Val) ref.Val {
// The concat list relies on the IsErrorOrUnknown checks against the input element to be
// performed by the `prevList` and/or `nextList`.
prev := l.prevList.Contains(elem)
// Short-circuit the return if the elem was found in the prev list.
if prev == True {
return prev
}
// Return if the elem was found in the next list.
next := l.nextList.Contains(elem)
if next == True {
return next
}
// Handle the case where an error or unknown was encountered before checking next.
if IsUnknownOrError(prev) {
return prev
}
// Otherwise, rely on the next value as the representative result.
return next
}
// ConvertToNative implements the ref.Val interface method.
func (l *concatList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
combined := NewDynamicList(l.TypeAdapter, l.Value().([]interface{}))
return combined.ConvertToNative(typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (l *concatList) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case ListType:
return l
case TypeType:
return ListType
}
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
}
// Equal implements the ref.Val interface method.
func (l *concatList) Equal(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return False
}
if l.Size() != otherList.Size() {
return False
}
var maybeErr ref.Val
for i := IntZero; i < l.Size().(Int); i++ {
thisElem := l.Get(i)
otherElem := otherList.Get(i)
elemEq := Equal(thisElem, otherElem)
if elemEq == False {
return False
}
if maybeErr == nil && IsUnknownOrError(elemEq) {
maybeErr = elemEq
}
}
if maybeErr != nil {
return maybeErr
}
return True
}
// Get implements the traits.Indexer interface method.
func (l *concatList) Get(index ref.Val) ref.Val {
ind, err := indexOrError(index)
if err != nil {
return ValOrErr(index, err.Error())
}
i := Int(ind)
if i < l.prevList.Size().(Int) {
return l.prevList.Get(i)
}
offset := i - l.prevList.Size().(Int)
return l.nextList.Get(offset)
}
// Iterator implements the traits.Iterable interface method.
func (l *concatList) Iterator() traits.Iterator {
return newListIterator(l)
}
// Size implements the traits.Sizer interface method.
func (l *concatList) Size() ref.Val {
return l.prevList.Size().(Int).Add(l.nextList.Size())
}
// Type implements the ref.Val interface method.
func (l *concatList) Type() ref.Type {
return ListType
}
// Value implements the ref.Val interface method.
func (l *concatList) Value() interface{} {
if l.value == nil {
merged := make([]interface{}, l.Size().(Int))
prevLen := l.prevList.Size().(Int)
for i := Int(0); i < prevLen; i++ {
merged[i] = l.prevList.Get(i).Value()
}
nextLen := l.nextList.Size().(Int)
for j := Int(0); j < nextLen; j++ {
merged[prevLen+j] = l.nextList.Get(j).Value()
}
l.value = merged
}
return l.value
}
func newListIterator(listValue traits.Lister) traits.Iterator {
return &listIterator{
listValue: listValue,
len: listValue.Size().(Int),
}
}
type listIterator struct {
*baseIterator
listValue traits.Lister
cursor Int
len Int
}
// HasNext implements the traits.Iterator interface method.
func (it *listIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *listIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
return it.listValue.Get(index)
}
return nil
}
func indexOrError(index ref.Val) (int, error) {
switch iv := index.(type) {
case Int:
return int(iv), nil
case Double:
if ik, ok := doubleToInt64Lossless(float64(iv)); ok {
return int(ik), nil
}
return -1, fmt.Errorf("unsupported index value %v in list", index)
case Uint:
if ik, ok := uint64ToInt64Lossless(uint64(iv)); ok {
return int(ik), nil
}
return -1, fmt.Errorf("unsupported index value %v in list", index)
default:
return -1, fmt.Errorf("unsupported index type '%s' in list", index.Type())
}
}

832
vendor/github.com/google/cel-go/common/types/map.go generated vendored Normal file
View File

@ -0,0 +1,832 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"github.com/stoewer/go-strcase"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// NewDynamicMap returns a traits.Mapper value with dynamic key, value pairs.
func NewDynamicMap(adapter ref.TypeAdapter, value interface{}) traits.Mapper {
refValue := reflect.ValueOf(value)
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newReflectMapAccessor(adapter, refValue),
value: value,
size: refValue.Len(),
}
}
// NewJSONStruct creates a traits.Mapper implementation backed by a JSON struct that has been
// encoded in protocol buffer form.
//
// The `adapter` argument provides type adaptation capabilities from proto to CEL.
func NewJSONStruct(adapter ref.TypeAdapter, value *structpb.Struct) traits.Mapper {
fields := value.GetFields()
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newJSONStructAccessor(adapter, fields),
value: value,
size: len(fields),
}
}
// NewRefValMap returns a specialized traits.Mapper with CEL valued keys and values.
func NewRefValMap(adapter ref.TypeAdapter, value map[ref.Val]ref.Val) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newRefValMapAccessor(value),
value: value,
size: len(value),
}
}
// NewStringInterfaceMap returns a specialized traits.Mapper with string keys and interface values.
func NewStringInterfaceMap(adapter ref.TypeAdapter, value map[string]interface{}) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newStringIfaceMapAccessor(adapter, value),
value: value,
size: len(value),
}
}
// NewStringStringMap returns a specialized traits.Mapper with string keys and values.
func NewStringStringMap(adapter ref.TypeAdapter, value map[string]string) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newStringMapAccessor(value),
value: value,
size: len(value),
}
}
// NewProtoMap returns a specialized traits.Mapper for handling protobuf map values.
func NewProtoMap(adapter ref.TypeAdapter, value *pb.Map) traits.Mapper {
return &protoMap{
TypeAdapter: adapter,
value: value,
}
}
var (
// MapType singleton.
MapType = NewTypeValue("map",
traits.ContainerType,
traits.IndexerType,
traits.IterableType,
traits.SizerType)
)
// mapAccessor is a private interface for finding values within a map and iterating over the keys.
// This interface implements portions of the API surface area required by the traits.Mapper
// interface.
type mapAccessor interface {
// Find returns a value, if one exists, for the input key.
//
// If the key is not found the function returns (nil, false).
Find(ref.Val) (ref.Val, bool)
// Iterator returns an Iterator over the map key set.
Iterator() traits.Iterator
}
// baseMap is a reflection based map implementation designed to handle a variety of map-like types.
//
// Since CEL is side-effect free, the base map represents an immutable object.
type baseMap struct {
// TypeAdapter used to convert keys and values accessed within the map.
ref.TypeAdapter
// mapAccessor interface implementation used to find and iterate over map keys.
mapAccessor
// value is the native Go value upon which the map type operators.
value interface{}
// size is the number of entries in the map.
size int
}
// Contains implements the traits.Container interface method.
func (m *baseMap) Contains(index ref.Val) ref.Val {
_, found := m.Find(index)
return Bool(found)
}
// ConvertToNative implements the ref.Val interface method.
func (m *baseMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the map is already assignable to the desired type return it, e.g. interfaces and
// maps with the same key value types.
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
return m.value, nil
}
if reflect.TypeOf(m).AssignableTo(typeDesc) {
return m, nil
}
switch typeDesc {
case anyValueType:
json, err := m.ConvertToNative(jsonStructType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonStructType:
jsonEntries, err :=
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonMap := &structpb.Struct{Fields: jsonEntries.(map[string]*structpb.Value)}
if typeDesc == jsonStructType {
return jsonMap, nil
}
return structpb.NewStructValue(jsonMap), nil
}
// Unwrap pointers, but track their use.
isPtr := false
if typeDesc.Kind() == reflect.Ptr {
tk := typeDesc
typeDesc = typeDesc.Elem()
if typeDesc.Kind() == reflect.Ptr {
return nil, fmt.Errorf("unsupported type conversion to '%v'", tk)
}
isPtr = true
}
switch typeDesc.Kind() {
// Map conversion.
case reflect.Map:
otherKey := typeDesc.Key()
otherElem := typeDesc.Elem()
nativeMap := reflect.MakeMapWithSize(typeDesc, m.size)
it := m.Iterator()
for it.HasNext() == True {
key := it.Next()
refKeyValue, err := key.ConvertToNative(otherKey)
if err != nil {
return nil, err
}
refElemValue, err := m.Get(key).ConvertToNative(otherElem)
if err != nil {
return nil, err
}
nativeMap.SetMapIndex(reflect.ValueOf(refKeyValue), reflect.ValueOf(refElemValue))
}
return nativeMap.Interface(), nil
case reflect.Struct:
nativeStructPtr := reflect.New(typeDesc)
nativeStruct := nativeStructPtr.Elem()
it := m.Iterator()
for it.HasNext() == True {
key := it.Next()
// Ensure the field name being referenced is exported.
// Only exported (public) field names can be set by reflection, where the name
// must be at least one character in length and start with an upper-case letter.
fieldName := key.ConvertToType(StringType)
if IsError(fieldName) {
return nil, fieldName.(*Err)
}
name := string(fieldName.(String))
name = strcase.UpperCamelCase(name)
fieldRef := nativeStruct.FieldByName(name)
if !fieldRef.IsValid() {
return nil, fmt.Errorf("type conversion error, no such field '%s' in type '%v'", name, typeDesc)
}
fieldValue, err := m.Get(key).ConvertToNative(fieldRef.Type())
if err != nil {
return nil, err
}
fieldRef.Set(reflect.ValueOf(fieldValue))
}
if isPtr {
return nativeStructPtr.Interface(), nil
}
return nativeStruct.Interface(), nil
}
return nil, fmt.Errorf("type conversion error from map to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (m *baseMap) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case MapType:
return m
case TypeType:
return MapType
}
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
}
// Equal implements the ref.Val interface method.
func (m *baseMap) Equal(other ref.Val) ref.Val {
otherMap, ok := other.(traits.Mapper)
if !ok {
return False
}
if m.Size() != otherMap.Size() {
return False
}
it := m.Iterator()
for it.HasNext() == True {
key := it.Next()
thisVal, _ := m.Find(key)
otherVal, found := otherMap.Find(key)
if !found {
return False
}
valEq := Equal(thisVal, otherVal)
if valEq == False {
return False
}
}
return True
}
// Get implements the traits.Indexer interface method.
func (m *baseMap) Get(key ref.Val) ref.Val {
v, found := m.Find(key)
if !found {
return ValOrErr(v, "no such key: %v", key)
}
return v
}
// Size implements the traits.Sizer interface method.
func (m *baseMap) Size() ref.Val {
return Int(m.size)
}
// Type implements the ref.Val interface method.
func (m *baseMap) Type() ref.Type {
return MapType
}
// Value implements the ref.Val interface method.
func (m *baseMap) Value() interface{} {
return m.value
}
func newJSONStructAccessor(adapter ref.TypeAdapter, st map[string]*structpb.Value) mapAccessor {
return &jsonStructAccessor{
TypeAdapter: adapter,
st: st,
}
}
type jsonStructAccessor struct {
ref.TypeAdapter
st map[string]*structpb.Value
}
// Find searches the json struct field map for the input key value and returns (value, true) if
// found.
//
// If the key is not found the function returns (nil, false).
func (a *jsonStructAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return nil, false
}
keyVal, found := a.st[string(strKey)]
if !found {
return nil, false
}
return a.NativeToValue(keyVal), true
}
// Iterator creates a new traits.Iterator from the set of JSON struct field names.
func (a *jsonStructAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.st))
i := 0
for k := range a.st {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
func newReflectMapAccessor(adapter ref.TypeAdapter, value reflect.Value) mapAccessor {
keyType := value.Type().Key()
return &reflectMapAccessor{
TypeAdapter: adapter,
refValue: value,
keyType: keyType,
}
}
type reflectMapAccessor struct {
ref.TypeAdapter
refValue reflect.Value
keyType reflect.Type
}
// Find converts the input key to a native Golang type and then uses reflection to find the key,
// returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
func (m *reflectMapAccessor) Find(key ref.Val) (ref.Val, bool) {
if m.refValue.Len() == 0 {
return nil, false
}
if keyVal, found := m.findInternal(key); found {
return keyVal, true
}
switch k := key.(type) {
// Double is not a valid proto map key type, so check for the key as an int or uint.
case Double:
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
if keyVal, found := m.findInternal(Int(ik)); found {
return keyVal, true
}
}
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
return m.findInternal(Uint(uk))
}
// map keys of type double are not supported.
case Int:
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
return m.findInternal(Uint(uk))
}
case Uint:
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
return m.findInternal(Int(ik))
}
}
return nil, false
}
// findInternal attempts to convert the incoming key to the map's internal native type
// and then returns the value, if found.
func (m *reflectMapAccessor) findInternal(key ref.Val) (ref.Val, bool) {
k, err := key.ConvertToNative(m.keyType)
if err != nil {
return nil, false
}
refKey := reflect.ValueOf(k)
val := m.refValue.MapIndex(refKey)
if val.IsValid() {
return m.NativeToValue(val.Interface()), true
}
return nil, false
}
// Iterator creates a Golang reflection based traits.Iterator.
func (m *reflectMapAccessor) Iterator() traits.Iterator {
return &mapIterator{
TypeAdapter: m.TypeAdapter,
mapKeys: m.refValue.MapRange(),
len: m.refValue.Len(),
}
}
func newRefValMapAccessor(mapVal map[ref.Val]ref.Val) mapAccessor {
return &refValMapAccessor{mapVal: mapVal}
}
type refValMapAccessor struct {
mapVal map[ref.Val]ref.Val
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
func (a *refValMapAccessor) Find(key ref.Val) (ref.Val, bool) {
if len(a.mapVal) == 0 {
return nil, false
}
if keyVal, found := a.mapVal[key]; found {
return keyVal, true
}
switch k := key.(type) {
case Double:
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
if keyVal, found := a.mapVal[Int(ik)]; found {
return keyVal, found
}
}
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
keyVal, found := a.mapVal[Uint(uk)]
return keyVal, found
}
// map keys of type double are not supported.
case Int:
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
keyVal, found := a.mapVal[Uint(uk)]
return keyVal, found
}
case Uint:
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
keyVal, found := a.mapVal[Int(ik)]
return keyVal, found
}
}
return nil, false
}
// Iterator produces a new traits.Iterator which iterates over the map keys via Golang reflection.
func (a *refValMapAccessor) Iterator() traits.Iterator {
return &mapIterator{
TypeAdapter: DefaultTypeAdapter,
mapKeys: reflect.ValueOf(a.mapVal).MapRange(),
len: len(a.mapVal),
}
}
func newStringMapAccessor(strMap map[string]string) mapAccessor {
return &stringMapAccessor{mapVal: strMap}
}
type stringMapAccessor struct {
mapVal map[string]string
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
func (a *stringMapAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return nil, false
}
keyVal, found := a.mapVal[string(strKey)]
if !found {
return nil, false
}
return String(keyVal), true
}
// Iterator creates a new traits.Iterator from the string key set of the map.
func (a *stringMapAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.mapVal))
i := 0
for k := range a.mapVal {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]interface{}) mapAccessor {
return &stringIfaceMapAccessor{
TypeAdapter: adapter,
mapVal: mapVal,
}
}
type stringIfaceMapAccessor struct {
ref.TypeAdapter
mapVal map[string]interface{}
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
func (a *stringIfaceMapAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return nil, false
}
keyVal, found := a.mapVal[string(strKey)]
if !found {
return nil, false
}
return a.NativeToValue(keyVal), true
}
// Iterator creates a new traits.Iterator from the string key set of the map.
func (a *stringIfaceMapAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.mapVal))
i := 0
for k := range a.mapVal {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
// protoMap is a specialized, separate implementation of the traits.Mapper interfaces tailored to
// accessing protoreflect.Map values.
type protoMap struct {
ref.TypeAdapter
value *pb.Map
}
// Contains returns whether the map contains the given key.
func (m *protoMap) Contains(key ref.Val) ref.Val {
_, found := m.Find(key)
return Bool(found)
}
// ConvertToNative implements the ref.Val interface method.
//
// Note, assignment to Golang struct types is not yet supported.
func (m *protoMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the map is already assignable to the desired type return it, e.g. interfaces and
// maps with the same key value types.
switch typeDesc {
case anyValueType:
json, err := m.ConvertToNative(jsonStructType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonStructType:
jsonEntries, err :=
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonMap := &structpb.Struct{
Fields: jsonEntries.(map[string]*structpb.Value)}
if typeDesc == jsonStructType {
return jsonMap, nil
}
return structpb.NewStructValue(jsonMap), nil
}
switch typeDesc.Kind() {
case reflect.Struct, reflect.Ptr:
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
return m.value, nil
}
if reflect.TypeOf(m).AssignableTo(typeDesc) {
return m, nil
}
}
if typeDesc.Kind() != reflect.Map {
return nil, fmt.Errorf("unsupported type conversion: %v to map", typeDesc)
}
keyType := m.value.KeyType.ReflectType()
valType := m.value.ValueType.ReflectType()
otherKeyType := typeDesc.Key()
otherValType := typeDesc.Elem()
mapVal := reflect.MakeMapWithSize(typeDesc, m.value.Len())
var err error
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
ntvKey := key.Interface()
ntvVal := val.Interface()
switch ntvVal.(type) {
case protoreflect.Message:
ntvVal = ntvVal.(protoreflect.Message).Interface()
}
if keyType == otherKeyType && valType == otherValType {
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
return true
}
celKey := m.NativeToValue(ntvKey)
celVal := m.NativeToValue(ntvVal)
ntvKey, err = celKey.ConvertToNative(otherKeyType)
if err != nil {
// early terminate the range loop.
return false
}
ntvVal, err = celVal.ConvertToNative(otherValType)
if err != nil {
// early terminate the range loop.
return false
}
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
return true
})
if err != nil {
return nil, err
}
return mapVal.Interface(), nil
}
// ConvertToType implements the ref.Val interface method.
func (m *protoMap) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case MapType:
return m
case TypeType:
return MapType
}
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
}
// Equal implements the ref.Val interface method.
func (m *protoMap) Equal(other ref.Val) ref.Val {
otherMap, ok := other.(traits.Mapper)
if !ok {
return False
}
if m.value.Map.Len() != int(otherMap.Size().(Int)) {
return False
}
var retVal ref.Val = True
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
keyVal := m.NativeToValue(key.Interface())
valVal := m.NativeToValue(val)
otherVal, found := otherMap.Find(keyVal)
if !found {
retVal = False
return false
}
valEq := Equal(valVal, otherVal)
if valEq != True {
retVal = valEq
return false
}
return true
})
return retVal
}
// Find returns whether the protoreflect.Map contains the input key.
//
// If the key is not found the function returns (nil, false).
func (m *protoMap) Find(key ref.Val) (ref.Val, bool) {
if keyVal, found := m.findInternal(key); found {
return keyVal, true
}
switch k := key.(type) {
// Double is not a valid proto map key type, so check for the key as an int or uint.
case Double:
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
if keyVal, found := m.findInternal(Int(ik)); found {
return keyVal, true
}
}
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
return m.findInternal(Uint(uk))
}
// map keys of type double are not supported.
case Int:
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
return m.findInternal(Uint(uk))
}
case Uint:
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
return m.findInternal(Int(ik))
}
}
return nil, false
}
// findInternal attempts to convert the incoming key to the map's internal native type
// and then returns the value, if found.
func (m *protoMap) findInternal(key ref.Val) (ref.Val, bool) {
// Convert the input key to the expected protobuf key type.
ntvKey, err := key.ConvertToNative(m.value.KeyType.ReflectType())
if err != nil {
return nil, false
}
// Use protoreflection to get the key value.
val := m.value.Get(protoreflect.ValueOf(ntvKey).MapKey())
if !val.IsValid() {
return nil, false
}
// Perform nominal type unwrapping from the input value.
switch v := val.Interface().(type) {
case protoreflect.List, protoreflect.Map:
// Maps do not support list or map values
return nil, false
default:
return m.NativeToValue(v), true
}
}
// Get implements the traits.Indexer interface method.
func (m *protoMap) Get(key ref.Val) ref.Val {
v, found := m.Find(key)
if !found {
return ValOrErr(v, "no such key: %v", key)
}
return v
}
// Iterator implements the traits.Iterable interface method.
func (m *protoMap) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]protoreflect.MapKey, 0, m.value.Len())
m.value.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
mapKeys = append(mapKeys, k)
return true
})
return &protoMapIterator{
TypeAdapter: m.TypeAdapter,
mapKeys: mapKeys,
len: m.value.Len(),
}
}
// Size returns the number of entries in the protoreflect.Map.
func (m *protoMap) Size() ref.Val {
return Int(m.value.Len())
}
// Type implements the ref.Val interface method.
func (m *protoMap) Type() ref.Type {
return MapType
}
// Value implements the ref.Val interface method.
func (m *protoMap) Value() interface{} {
return m.value
}
type mapIterator struct {
*baseIterator
ref.TypeAdapter
mapKeys *reflect.MapIter
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *mapIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *mapIterator) Next() ref.Val {
if it.HasNext() == True && it.mapKeys.Next() {
it.cursor++
refKey := it.mapKeys.Key()
return it.NativeToValue(refKey.Interface())
}
return nil
}
type protoMapIterator struct {
*baseIterator
ref.TypeAdapter
mapKeys []protoreflect.MapKey
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *protoMapIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *protoMapIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
refKey := it.mapKeys[index]
return it.NativeToValue(refKey.Interface())
}
return nil
}
type stringKeyIterator struct {
*baseIterator
mapKeys []string
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *stringKeyIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *stringKeyIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
return String(it.mapKeys[index])
}
return nil
}

97
vendor/github.com/google/cel-go/common/types/null.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"google.golang.org/protobuf/proto"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// Null type implementation.
type Null structpb.NullValue
var (
// NullType singleton.
NullType = NewTypeValue("null_type")
// NullValue singleton.
NullValue = Null(structpb.NullValue_NULL_VALUE)
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
)
// ConvertToNative implements ref.Val.ConvertToNative.
func (n Null) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Int32:
return reflect.ValueOf(n).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Convert to a JSON-null before packing to an Any field since the enum value for JSON
// null cannot be packed directly.
pb, err := n.ConvertToNative(jsonValueType)
if err != nil {
return nil, err
}
return anypb.New(pb.(proto.Message))
case jsonValueType:
return structpb.NewNullValue(), nil
}
case reflect.Interface:
nv := n.Value()
if reflect.TypeOf(nv).Implements(typeDesc) {
return nv, nil
}
if reflect.TypeOf(n).Implements(typeDesc) {
return n, nil
}
}
// If the type conversion isn't supported return an error.
return nil, fmt.Errorf("type conversion error from '%v' to '%v'", NullType, typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (n Null) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String("null")
case NullType:
return n
case TypeType:
return NullType
}
return NewErr("type conversion error from '%s' to '%s'", NullType, typeVal)
}
// Equal implements ref.Val.Equal.
func (n Null) Equal(other ref.Val) ref.Val {
return Bool(NullType == other.Type())
}
// Type implements ref.Val.Type.
func (n Null) Type() ref.Type {
return NullType
}
// Value implements ref.Val.Value.
func (n Null) Value() interface{} {
return structpb.NullValue_NULL_VALUE
}

159
vendor/github.com/google/cel-go/common/types/object.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
type protoObj struct {
ref.TypeAdapter
value proto.Message
typeDesc *pb.TypeDescription
typeValue *TypeValue
}
// NewObject returns an object based on a proto.Message value which handles
// conversion between protobuf type values and expression type values.
// Objects support indexing and iteration.
//
// Note: the type value is pulled from the list of registered types within the
// type provider. If the proto type is not registered within the type provider,
// then this will result in an error within the type adapter / provider.
func NewObject(adapter ref.TypeAdapter,
typeDesc *pb.TypeDescription,
typeValue *TypeValue,
value proto.Message) ref.Val {
return &protoObj{
TypeAdapter: adapter,
value: value,
typeDesc: typeDesc,
typeValue: typeValue}
}
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
srcPB := o.value
if reflect.TypeOf(srcPB).AssignableTo(typeDesc) {
return srcPB, nil
}
if reflect.TypeOf(o).AssignableTo(typeDesc) {
return o, nil
}
switch typeDesc {
case anyValueType:
_, isAny := srcPB.(*anypb.Any)
if isAny {
return srcPB, nil
}
return anypb.New(srcPB)
case jsonValueType:
// Marshal the proto to JSON first, and then rehydrate as protobuf.Value as there is no
// support for direct conversion from proto.Message to protobuf.Value.
bytes, err := protojson.Marshal(srcPB)
if err != nil {
return nil, err
}
json := &structpb.Value{}
err = protojson.Unmarshal(bytes, json)
if err != nil {
return nil, err
}
return json, nil
default:
if typeDesc == o.typeDesc.ReflectType() {
return o.value, nil
}
if typeDesc.Kind() == reflect.Ptr {
val := reflect.New(typeDesc.Elem()).Interface()
dstPB, ok := val.(proto.Message)
if ok {
err := pb.Merge(dstPB, srcPB)
if err != nil {
return nil, fmt.Errorf("type conversion error: %v", err)
}
return dstPB, nil
}
}
}
return nil, fmt.Errorf("type conversion error from '%T' to '%v'", o.value, typeDesc)
}
func (o *protoObj) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
default:
if o.Type().TypeName() == typeVal.TypeName() {
return o
}
case TypeType:
return o.typeValue
}
return NewErr("type conversion error from '%s' to '%s'", o.typeDesc.Name(), typeVal)
}
func (o *protoObj) Equal(other ref.Val) ref.Val {
otherPB, ok := other.Value().(proto.Message)
return Bool(ok && pb.Equal(o.value, otherPB))
}
// IsSet tests whether a field which is defined is set to a non-default value.
func (o *protoObj) IsSet(field ref.Val) ref.Val {
protoFieldName, ok := field.(String)
if !ok {
return MaybeNoSuchOverloadErr(field)
}
protoFieldStr := string(protoFieldName)
fd, found := o.typeDesc.FieldByName(protoFieldStr)
if !found {
return NewErr("no such field '%s'", field)
}
if fd.IsSet(o.value) {
return True
}
return False
}
func (o *protoObj) Get(index ref.Val) ref.Val {
protoFieldName, ok := index.(String)
if !ok {
return MaybeNoSuchOverloadErr(index)
}
protoFieldStr := string(protoFieldName)
fd, found := o.typeDesc.FieldByName(protoFieldStr)
if !found {
return NewErr("no such field '%s'", index)
}
fv, err := fd.GetFrom(o.value)
if err != nil {
return NewErr(err.Error())
}
return o.NativeToValue(fv)
}
func (o *protoObj) Type() ref.Type {
return o.typeValue
}
func (o *protoObj) Value() interface{} {
return o.value
}

View File

@ -0,0 +1,389 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"math"
"time"
)
var (
doubleTwoTo64 = math.Ldexp(1.0, 64)
)
// addInt64Checked performs addition with overflow detection of two int64 values.
//
// If the operation fails the error return value will be non-nil.
func addInt64Checked(x, y int64) (int64, error) {
if (y > 0 && x > math.MaxInt64-y) || (y < 0 && x < math.MinInt64-y) {
return 0, errIntOverflow
}
return x + y, nil
}
// subtractInt64Checked performs subtraction with overflow detection of two int64 values.
//
// If the operation fails the error return value will be non-nil.
func subtractInt64Checked(x, y int64) (int64, error) {
if (y < 0 && x > math.MaxInt64+y) || (y > 0 && x < math.MinInt64+y) {
return 0, errIntOverflow
}
return x - y, nil
}
// negateInt64Checked performs negation with overflow detection of an int64.
//
// If the operation fails the error return value will be non-nil.
func negateInt64Checked(x int64) (int64, error) {
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 {
return 0, errIntOverflow
}
return -x, nil
}
// multiplyInt64Checked performs multiplication with overflow detection of two int64 value.
//
// If the operation fails the error return value will be non-nil.
func multiplyInt64Checked(x, y int64) (int64, error) {
// Detecting multiplication overflow is more complicated than the others. The first two detect
// attempting to negate MinInt64, which would result in MaxInt64+1. The other four detect normal
// overflow conditions.
if (x == -1 && y == math.MinInt64) || (y == -1 && x == math.MinInt64) ||
// x is positive, y is positive
(x > 0 && y > 0 && x > math.MaxInt64/y) ||
// x is positive, y is negative
(x > 0 && y < 0 && y < math.MinInt64/x) ||
// x is negative, y is positive
(x < 0 && y > 0 && x < math.MinInt64/y) ||
// x is negative, y is negative
(x < 0 && y < 0 && y < math.MaxInt64/x) {
return 0, errIntOverflow
}
return x * y, nil
}
// divideInt64Checked performs division with overflow detection of two int64 values,
// as well as a division by zero check.
//
// If the operation fails the error return value will be non-nil.
func divideInt64Checked(x, y int64) (int64, error) {
// Division by zero.
if y == 0 {
return 0, errDivideByZero
}
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 && y == -1 {
return 0, errIntOverflow
}
return x / y, nil
}
// moduloInt64Checked performs modulo with overflow detection of two int64 values
// as well as a modulus by zero check.
//
// If the operation fails the error return value will be non-nil.
func moduloInt64Checked(x, y int64) (int64, error) {
// Modulus by zero.
if y == 0 {
return 0, errModulusByZero
}
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 && y == -1 {
return 0, errIntOverflow
}
return x % y, nil
}
// addUint64Checked performs addition with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addUint64Checked(x, y uint64) (uint64, error) {
if y > 0 && x > math.MaxUint64-y {
return 0, errUintOverflow
}
return x + y, nil
}
// subtractUint64Checked performs subtraction with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractUint64Checked(x, y uint64) (uint64, error) {
if y > x {
return 0, errUintOverflow
}
return x - y, nil
}
// multiplyUint64Checked performs multiplication with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func multiplyUint64Checked(x, y uint64) (uint64, error) {
if y != 0 && x > math.MaxUint64/y {
return 0, errUintOverflow
}
return x * y, nil
}
// divideUint64Checked performs division with a test for division by zero.
//
// If the operation fails the error return value will be non-nil.
func divideUint64Checked(x, y uint64) (uint64, error) {
if y == 0 {
return 0, errDivideByZero
}
return x / y, nil
}
// moduloUint64Checked performs modulo with a test for modulus by zero.
//
// If the operation fails the error return value will be non-nil.
func moduloUint64Checked(x, y uint64) (uint64, error) {
if y == 0 {
return 0, errModulusByZero
}
return x % y, nil
}
// addDurationChecked performs addition with overflow detection of two time.Durations.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addDurationChecked(x, y time.Duration) (time.Duration, error) {
val, err := addInt64Checked(int64(x), int64(y))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// subtractDurationChecked performs subtraction with overflow detection of two time.Durations.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractDurationChecked(x, y time.Duration) (time.Duration, error) {
val, err := subtractInt64Checked(int64(x), int64(y))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// negateDurationChecked performs negation with overflow detection of a time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func negateDurationChecked(x time.Duration) (time.Duration, error) {
val, err := negateInt64Checked(int64(x))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// addDurationChecked performs addition with overflow detection of a time.Time and time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
// This is tricky. A time is represented as (int64, int32) where the first is seconds and second
// is nanoseconds. A duration is int64 representing nanoseconds. We cannot normalize time to int64
// as it could potentially overflow. The only way to proceed is to break time and duration into
// second and nanosecond components.
// First we break time into its components by truncating and subtracting.
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Second we break duration into its components by dividing and modulo.
sec2 := int64(y) / int64(time.Second) // Truncate to seconds.
nsec2 := int64(y) % int64(time.Second) // Get remainder.
// Add seconds first, detecting any overflow.
sec, err := addInt64Checked(sec1, sec2)
if err != nil {
return time.Time{}, err
}
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
nsec := nsec1 + nsec2
// We need to normalize nanoseconds to be positive and carry extra nanoseconds to seconds.
// Adapted from time.Unix(int64, int64).
if nsec < 0 || nsec >= int64(time.Second) {
// Add seconds.
sec, err = addInt64Checked(sec, nsec/int64(time.Second))
if err != nil {
return time.Time{}, err
}
nsec -= (nsec / int64(time.Second)) * int64(time.Second)
if nsec < 0 {
// Subtract an extra second
sec, err = addInt64Checked(sec, -1)
if err != nil {
return time.Time{}, err
}
nsec += int64(time.Second)
}
}
// Check if the the number of seconds from Unix epoch is within our acceptable range.
if sec < minUnixTime || sec > maxUnixTime {
return time.Time{}, errTimestampOverflow
}
// Return resulting time and propagate time zone.
return time.Unix(sec, nsec).In(x.Location()), nil
}
// subtractTimeChecked performs subtraction with overflow detection of two time.Time.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractTimeChecked(x, y time.Time) (time.Duration, error) {
// Similar to addTimeDurationOverflow() above.
// First we break time into its components by truncating and subtracting.
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Second we break duration into its components by truncating and subtracting.
sec2 := y.Truncate(time.Second).Unix() // Truncate to seconds.
nsec2 := y.Sub(y.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Subtract seconds first, detecting any overflow.
sec, err := subtractInt64Checked(sec1, sec2)
if err != nil {
return time.Duration(0), err
}
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
nsec := nsec1 - nsec2
// Scale seconds to nanoseconds detecting overflow.
tsec, err := multiplyInt64Checked(sec, int64(time.Second))
if err != nil {
return time.Duration(0), err
}
// Lastly we need to add the two nanoseconds together.
val, err := addInt64Checked(tsec, nsec)
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// subtractTimeDurationChecked performs subtraction with overflow detection of a time.Time and
// time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
// The easiest way to implement this is to negate y and add them.
// x - y = x + -y
val, err := negateDurationChecked(y)
if err != nil {
return time.Time{}, err
}
return addTimeDurationChecked(x, val)
}
// doubleToInt64Checked converts a double to an int64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func doubleToInt64Checked(v float64) (int64, error) {
if math.IsInf(v, 0) || math.IsNaN(v) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
return 0, errIntOverflow
}
return int64(v), nil
}
// doubleToInt64Checked converts a double to a uint64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func doubleToUint64Checked(v float64) (uint64, error) {
if math.IsInf(v, 0) || math.IsNaN(v) || v < 0 || v >= doubleTwoTo64 {
return 0, errUintOverflow
}
return uint64(v), nil
}
// int64ToUint64Checked converts an int64 to a uint64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func int64ToUint64Checked(v int64) (uint64, error) {
if v < 0 {
return 0, errUintOverflow
}
return uint64(v), nil
}
// int64ToInt32Checked converts an int64 to an int32 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func int64ToInt32Checked(v int64) (int32, error) {
if v < math.MinInt32 || v > math.MaxInt32 {
return 0, errIntOverflow
}
return int32(v), nil
}
// uint64ToUint32Checked converts a uint64 to a uint32 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func uint64ToUint32Checked(v uint64) (uint32, error) {
if v > math.MaxUint32 {
return 0, errUintOverflow
}
return uint32(v), nil
}
// uint64ToInt64Checked converts a uint64 to an int64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func uint64ToInt64Checked(v uint64) (int64, error) {
if v > math.MaxInt64 {
return 0, errIntOverflow
}
return int64(v), nil
}
func doubleToUint64Lossless(v float64) (uint64, bool) {
u, err := doubleToUint64Checked(v)
if err != nil {
return 0, false
}
if float64(u) != v {
return 0, false
}
return u, true
}
func doubleToInt64Lossless(v float64) (int64, bool) {
i, err := doubleToInt64Checked(v)
if err != nil {
return 0, false
}
if float64(i) != v {
return 0, false
}
return i, true
}
func int64ToUint64Lossless(v int64) (uint64, bool) {
u, err := int64ToUint64Checked(v)
return u, err == nil
}
func uint64ToInt64Lossless(v uint64) (int64, bool) {
i, err := uint64ToInt64Checked(v)
return i, err == nil
}

View File

@ -0,0 +1,53 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"checked.go",
"enum.go",
"equal.go",
"file.go",
"pb.go",
"type.go",
],
importpath = "github.com/google/cel-go/common/types/pb",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//encoding/protowire:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//reflect/protoregistry:go_default_library",
"@org_golang_google_protobuf//types/dynamicpb:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"equal_test.go",
"file_test.go",
"pb_test.go",
"type_test.go",
],
embed = [":go_default_library"],
deps = [
"//checker/decls:go_default_library",
"//test/proto2pb:test_all_types_go_proto",
"//test/proto3pb:test_all_types_go_proto",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
],
)

View File

@ -0,0 +1,93 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pb
import (
"google.golang.org/protobuf/reflect/protoreflect"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
emptypb "google.golang.org/protobuf/types/known/emptypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
var (
// CheckedPrimitives map from proto field descriptor type to expr.Type.
CheckedPrimitives = map[protoreflect.Kind]*exprpb.Type{
protoreflect.BoolKind: checkedBool,
protoreflect.BytesKind: checkedBytes,
protoreflect.DoubleKind: checkedDouble,
protoreflect.FloatKind: checkedDouble,
protoreflect.Int32Kind: checkedInt,
protoreflect.Int64Kind: checkedInt,
protoreflect.Sint32Kind: checkedInt,
protoreflect.Sint64Kind: checkedInt,
protoreflect.Uint32Kind: checkedUint,
protoreflect.Uint64Kind: checkedUint,
protoreflect.Fixed32Kind: checkedUint,
protoreflect.Fixed64Kind: checkedUint,
protoreflect.Sfixed32Kind: checkedInt,
protoreflect.Sfixed64Kind: checkedInt,
protoreflect.StringKind: checkedString}
// CheckedWellKnowns map from qualified proto type name to expr.Type for
// well-known proto types.
CheckedWellKnowns = map[string]*exprpb.Type{
// Wrapper types.
"google.protobuf.BoolValue": checkedWrap(checkedBool),
"google.protobuf.BytesValue": checkedWrap(checkedBytes),
"google.protobuf.DoubleValue": checkedWrap(checkedDouble),
"google.protobuf.FloatValue": checkedWrap(checkedDouble),
"google.protobuf.Int64Value": checkedWrap(checkedInt),
"google.protobuf.Int32Value": checkedWrap(checkedInt),
"google.protobuf.UInt64Value": checkedWrap(checkedUint),
"google.protobuf.UInt32Value": checkedWrap(checkedUint),
"google.protobuf.StringValue": checkedWrap(checkedString),
// Well-known types.
"google.protobuf.Any": checkedAny,
"google.protobuf.Duration": checkedDuration,
"google.protobuf.Timestamp": checkedTimestamp,
// Json types.
"google.protobuf.ListValue": checkedListDyn,
"google.protobuf.NullValue": checkedNull,
"google.protobuf.Struct": checkedMapStringDyn,
"google.protobuf.Value": checkedDyn,
}
// common types
checkedDyn = &exprpb.Type{TypeKind: &exprpb.Type_Dyn{Dyn: &emptypb.Empty{}}}
// Wrapper and primitive types.
checkedBool = checkedPrimitive(exprpb.Type_BOOL)
checkedBytes = checkedPrimitive(exprpb.Type_BYTES)
checkedDouble = checkedPrimitive(exprpb.Type_DOUBLE)
checkedInt = checkedPrimitive(exprpb.Type_INT64)
checkedString = checkedPrimitive(exprpb.Type_STRING)
checkedUint = checkedPrimitive(exprpb.Type_UINT64)
// Well-known type equivalents.
checkedAny = checkedWellKnown(exprpb.Type_ANY)
checkedDuration = checkedWellKnown(exprpb.Type_DURATION)
checkedTimestamp = checkedWellKnown(exprpb.Type_TIMESTAMP)
// Json-based type equivalents.
checkedNull = &exprpb.Type{
TypeKind: &exprpb.Type_Null{
Null: structpb.NullValue_NULL_VALUE}}
checkedListDyn = &exprpb.Type{
TypeKind: &exprpb.Type_ListType_{
ListType: &exprpb.Type_ListType{ElemType: checkedDyn}}}
checkedMapStringDyn = &exprpb.Type{
TypeKind: &exprpb.Type_MapType_{
MapType: &exprpb.Type_MapType{
KeyType: checkedString,
ValueType: checkedDyn}}}
)

View File

@ -0,0 +1,44 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pb
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// NewEnumValueDescription produces an enum value description with the fully qualified enum value
// name and the enum value descriptor.
func NewEnumValueDescription(name string, desc protoreflect.EnumValueDescriptor) *EnumValueDescription {
return &EnumValueDescription{
enumValueName: name,
desc: desc,
}
}
// EnumValueDescription maps a fully-qualified enum value name to its numeric value.
type EnumValueDescription struct {
enumValueName string
desc protoreflect.EnumValueDescriptor
}
// Name returns the fully-qualified identifier name for the enum value.
func (ed *EnumValueDescription) Name() string {
return ed.enumValueName
}
// Value returns the (numeric) value of the enum.
func (ed *EnumValueDescription) Value() int32 {
return int32(ed.desc.Number())
}

View File

@ -0,0 +1,206 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pb
import (
"bytes"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
anypb "google.golang.org/protobuf/types/known/anypb"
)
// Equal returns whether two proto.Message instances are equal using the following criteria:
//
// - Messages must share the same instance of the type descriptor
// - Known set fields are compared using semantics equality
// - Bytes are compared using bytes.Equal
// - Scalar values are compared with operator ==
// - List and map types are equal if they have the same length and all elements are equal
// - Messages are equal if they share the same descriptor and all set fields are equal
// - Unknown fields are compared using byte equality
// - NaN values are not equal to each other
// - google.protobuf.Any values are unpacked before comparison
// - If the type descriptor for a protobuf.Any cannot be found, byte equality is used rather than
// semantic equality.
//
// This method of proto equality mirrors the behavior of the C++ protobuf MessageDifferencer
// whereas the golang proto.Equal implementation mirrors the Java protobuf equals() methods
// behaviors which needed to treat NaN values as equal due to Java semantics.
func Equal(x, y proto.Message) bool {
if x == nil || y == nil {
return x == nil && y == nil
}
xRef := x.ProtoReflect()
yRef := y.ProtoReflect()
return equalMessage(xRef, yRef)
}
func equalMessage(mx, my protoreflect.Message) bool {
// Note, the original proto.Equal upon which this implementation is based does not specifically handle the
// case when both messages are invalid. It is assumed that the descriptors will be equal and that byte-wise
// comparison will be used, though the semantics of validity are neither clear, nor promised within the
// proto.Equal implementation.
if mx.IsValid() != my.IsValid() || mx.Descriptor() != my.Descriptor() {
return false
}
// This is an innovation on the default proto.Equal where protobuf.Any values are unpacked before comparison
// as otherwise the Any values are compared by bytes rather than structurally.
if isAny(mx) && isAny(my) {
ax := mx.Interface().(*anypb.Any)
ay := my.Interface().(*anypb.Any)
// If the values are not the same type url, return false.
if ax.GetTypeUrl() != ay.GetTypeUrl() {
return false
}
// If the values are byte equal, then return true.
if bytes.Equal(ax.GetValue(), ay.GetValue()) {
return true
}
// Otherwise fall through to the semantic comparison of the any values.
x, err := ax.UnmarshalNew()
if err != nil {
return false
}
y, err := ay.UnmarshalNew()
if err != nil {
return false
}
// Recursively compare the unwrapped messages to ensure nested Any values are unwrapped accordingly.
return equalMessage(x.ProtoReflect(), y.ProtoReflect())
}
// Walk the set fields to determine field-wise equality
nx := 0
equal := true
mx.Range(func(fd protoreflect.FieldDescriptor, vx protoreflect.Value) bool {
nx++
equal = my.Has(fd) && equalField(fd, vx, my.Get(fd))
return equal
})
if !equal {
return false
}
// Establish the count of set fields on message y
ny := 0
my.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
ny++
return true
})
// If the number of set fields is not equal return false.
if nx != ny {
return false
}
return equalUnknown(mx.GetUnknown(), my.GetUnknown())
}
func equalField(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
switch {
case fd.IsMap():
return equalMap(fd, x.Map(), y.Map())
case fd.IsList():
return equalList(fd, x.List(), y.List())
default:
return equalValue(fd, x, y)
}
}
func equalMap(fd protoreflect.FieldDescriptor, x, y protoreflect.Map) bool {
if x.Len() != y.Len() {
return false
}
equal := true
x.Range(func(k protoreflect.MapKey, vx protoreflect.Value) bool {
vy := y.Get(k)
equal = y.Has(k) && equalValue(fd.MapValue(), vx, vy)
return equal
})
return equal
}
func equalList(fd protoreflect.FieldDescriptor, x, y protoreflect.List) bool {
if x.Len() != y.Len() {
return false
}
for i := x.Len() - 1; i >= 0; i-- {
if !equalValue(fd, x.Get(i), y.Get(i)) {
return false
}
}
return true
}
func equalValue(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
switch fd.Kind() {
case protoreflect.BoolKind:
return x.Bool() == y.Bool()
case protoreflect.EnumKind:
return x.Enum() == y.Enum()
case protoreflect.Int32Kind, protoreflect.Sint32Kind,
protoreflect.Int64Kind, protoreflect.Sint64Kind,
protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
return x.Int() == y.Int()
case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
return x.Uint() == y.Uint()
case protoreflect.FloatKind, protoreflect.DoubleKind:
return x.Float() == y.Float()
case protoreflect.StringKind:
return x.String() == y.String()
case protoreflect.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case protoreflect.MessageKind, protoreflect.GroupKind:
return equalMessage(x.Message(), y.Message())
default:
return x.Interface() == y.Interface()
}
}
func equalUnknown(x, y protoreflect.RawFields) bool {
lenX := len(x)
lenY := len(y)
if lenX != lenY {
return false
}
if lenX == 0 {
return true
}
if bytes.Equal([]byte(x), []byte(y)) {
return true
}
mx := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
my := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
for len(x) > 0 {
fnum, _, n := protowire.ConsumeField(x)
mx[fnum] = append(mx[fnum], x[:n]...)
x = x[n:]
}
for len(y) > 0 {
fnum, _, n := protowire.ConsumeField(y)
my[fnum] = append(my[fnum], y[:n]...)
y = y[n:]
}
return reflect.DeepEqual(mx, my)
}
func isAny(m protoreflect.Message) bool {
return string(m.Descriptor().FullName()) == "google.protobuf.Any"
}

141
vendor/github.com/google/cel-go/common/types/pb/file.go generated vendored Normal file
View File

@ -0,0 +1,141 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pb
import (
"fmt"
"google.golang.org/protobuf/reflect/protoreflect"
)
// NewFileDescription returns a FileDescription instance with a complete listing of all the message
// types and enum values declared within any scope in the file.
func NewFileDescription(fileDesc protoreflect.FileDescriptor, pbdb *Db) *FileDescription {
metadata := collectFileMetadata(fileDesc)
enums := make(map[string]*EnumValueDescription)
for name, enumVal := range metadata.enumValues {
enums[name] = NewEnumValueDescription(name, enumVal)
}
types := make(map[string]*TypeDescription)
for name, msgType := range metadata.msgTypes {
types[name] = NewTypeDescription(name, msgType)
}
return &FileDescription{
types: types,
enums: enums,
}
}
// FileDescription holds a map of all types and enum values declared within a proto file.
type FileDescription struct {
types map[string]*TypeDescription
enums map[string]*EnumValueDescription
}
// GetEnumDescription returns an EnumDescription for a qualified enum value
// name declared within the .proto file.
func (fd *FileDescription) GetEnumDescription(enumName string) (*EnumValueDescription, bool) {
ed, found := fd.enums[sanitizeProtoName(enumName)]
return ed, found
}
// GetEnumNames returns the string names of all enum values in the file.
func (fd *FileDescription) GetEnumNames() []string {
enumNames := make([]string, len(fd.enums))
i := 0
for _, e := range fd.enums {
enumNames[i] = e.Name()
i++
}
return enumNames
}
// GetTypeDescription returns a TypeDescription for a qualified protobuf message type name
// declared within the .proto file.
func (fd *FileDescription) GetTypeDescription(typeName string) (*TypeDescription, bool) {
td, found := fd.types[sanitizeProtoName(typeName)]
return td, found
}
// GetTypeNames returns the list of all type names contained within the file.
func (fd *FileDescription) GetTypeNames() []string {
typeNames := make([]string, len(fd.types))
i := 0
for _, t := range fd.types {
typeNames[i] = t.Name()
i++
}
return typeNames
}
// sanitizeProtoName strips the leading '.' from the proto message name.
func sanitizeProtoName(name string) string {
if name != "" && name[0] == '.' {
return name[1:]
}
return name
}
// fileMetadata is a flattened view of message types and enum values within a file descriptor.
type fileMetadata struct {
// msgTypes maps from fully-qualified message name to descriptor.
msgTypes map[string]protoreflect.MessageDescriptor
// enumValues maps from fully-qualified enum value to enum value descriptor.
enumValues map[string]protoreflect.EnumValueDescriptor
// TODO: support enum type definitions for use in future type-check enhancements.
}
// collectFileMetadata traverses the proto file object graph to collect message types and enum
// values and index them by their fully qualified names.
func collectFileMetadata(fileDesc protoreflect.FileDescriptor) *fileMetadata {
msgTypes := make(map[string]protoreflect.MessageDescriptor)
enumValues := make(map[string]protoreflect.EnumValueDescriptor)
collectMsgTypes(fileDesc.Messages(), msgTypes, enumValues)
collectEnumValues(fileDesc.Enums(), enumValues)
return &fileMetadata{
msgTypes: msgTypes,
enumValues: enumValues,
}
}
// collectMsgTypes recursively collects messages, nested messages, and nested enums into a map of
// fully qualified protobuf names to descriptors.
func collectMsgTypes(msgTypes protoreflect.MessageDescriptors, msgTypeMap map[string]protoreflect.MessageDescriptor, enumValueMap map[string]protoreflect.EnumValueDescriptor) {
for i := 0; i < msgTypes.Len(); i++ {
msgType := msgTypes.Get(i)
msgTypeMap[string(msgType.FullName())] = msgType
nestedMsgTypes := msgType.Messages()
if nestedMsgTypes.Len() != 0 {
collectMsgTypes(nestedMsgTypes, msgTypeMap, enumValueMap)
}
nestedEnumTypes := msgType.Enums()
if nestedEnumTypes.Len() != 0 {
collectEnumValues(nestedEnumTypes, enumValueMap)
}
}
}
// collectEnumValues accumulates the enum values within an enum declaration.
func collectEnumValues(enumTypes protoreflect.EnumDescriptors, enumValueMap map[string]protoreflect.EnumValueDescriptor) {
for i := 0; i < enumTypes.Len(); i++ {
enumType := enumTypes.Get(i)
enumTypeValues := enumType.Values()
for j := 0; j < enumTypeValues.Len(); j++ {
enumValue := enumTypeValues.Get(j)
enumValueName := fmt.Sprintf("%s.%s", string(enumType.FullName()), string(enumValue.Name()))
enumValueMap[enumValueName] = enumValue
}
}
}

223
vendor/github.com/google/cel-go/common/types/pb/pb.go generated vendored Normal file
View File

@ -0,0 +1,223 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package pb reflects over protocol buffer descriptors to generate objects
// that simplify type, enum, and field lookup.
package pb
import (
"fmt"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
anypb "google.golang.org/protobuf/types/known/anypb"
durpb "google.golang.org/protobuf/types/known/durationpb"
emptypb "google.golang.org/protobuf/types/known/emptypb"
structpb "google.golang.org/protobuf/types/known/structpb"
tspb "google.golang.org/protobuf/types/known/timestamppb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Db maps from file / message / enum name to file description.
//
// Each Db is isolated from each other, and while information about protobuf descriptors may be
// fetched from the global protobuf registry, no descriptors are added to this registry, else
// the isolation guarantees of the Db object would be violated.
type Db struct {
revFileDescriptorMap map[string]*FileDescription
// files contains the deduped set of FileDescriptions whose types are contained in the pb.Db.
files []*FileDescription
}
var (
// DefaultDb used at evaluation time or unless overridden at check time.
DefaultDb = &Db{
revFileDescriptorMap: make(map[string]*FileDescription),
files: []*FileDescription{},
}
)
// Merge will copy the source proto message into the destination, or error if the merge cannot be completed.
//
// Unlike the proto.Merge, this method will fallback to proto.Marshal/Unmarshal of the two proto messages do not
// share the same instance of their type descriptor.
func Merge(dstPB, srcPB proto.Message) error {
src, dst := srcPB.ProtoReflect(), dstPB.ProtoReflect()
if src.Descriptor() == dst.Descriptor() {
proto.Merge(dstPB, srcPB)
return nil
}
if src.Descriptor().FullName() != dst.Descriptor().FullName() {
return fmt.Errorf("pb.Merge() arguments must be the same type. got: %v, %v",
dst.Descriptor().FullName(), src.Descriptor().FullName())
}
bytes, err := proto.Marshal(srcPB)
if err != nil {
return fmt.Errorf("pb.Merge(dstPB, srcPB) failed to marshal source proto: %v", err)
}
err = proto.Unmarshal(bytes, dstPB)
if err != nil {
return fmt.Errorf("pb.Merge(dstPB, srcPB) failed to unmarshal to dest proto: %v", err)
}
return nil
}
// NewDb creates a new `pb.Db` with an empty type name to file description map.
func NewDb() *Db {
pbdb := &Db{
revFileDescriptorMap: make(map[string]*FileDescription),
files: []*FileDescription{},
}
// The FileDescription objects in the default db contain lazily initialized TypeDescription
// values which may point to the state contained in the DefaultDb irrespective of this shallow
// copy; however, the type graph for a field is idempotently computed, and is guaranteed to
// only be initialized once thanks to atomic values within the TypeDescription objects, so it
// is safe to share these values across instances.
for k, v := range DefaultDb.revFileDescriptorMap {
pbdb.revFileDescriptorMap[k] = v
}
pbdb.files = append(pbdb.files, DefaultDb.files...)
return pbdb
}
// Copy creates a copy of the current database with its own internal descriptor mapping.
func (pbdb *Db) Copy() *Db {
copy := NewDb()
for k, v := range pbdb.revFileDescriptorMap {
copy.revFileDescriptorMap[k] = v
}
for _, f := range pbdb.files {
hasFile := false
for _, f2 := range copy.files {
if f2 == f {
hasFile = true
}
}
if !hasFile {
copy.files = append(copy.files, f)
}
}
return copy
}
// FileDescriptions returns the set of file descriptions associated with this db.
func (pbdb *Db) FileDescriptions() []*FileDescription {
return pbdb.files
}
// RegisterDescriptor produces a `FileDescription` from a `FileDescriptor` and registers the
// message and enum types into the `pb.Db`.
func (pbdb *Db) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) (*FileDescription, error) {
fd, found := pbdb.revFileDescriptorMap[fileDesc.Path()]
if found {
return fd, nil
}
// Make sure to search the global registry to see if a protoreflect.FileDescriptor for
// the file specified has been linked into the binary. If so, use the copy of the descriptor
// from the global cache.
//
// Note: Proto reflection relies on descriptor values being object equal rather than object
// equivalence. This choice means that a FieldDescriptor generated from a FileDescriptorProto
// will be incompatible with the FieldDescriptor in the global registry and any message created
// from that global registry.
globalFD, err := protoregistry.GlobalFiles.FindFileByPath(fileDesc.Path())
if err == nil {
fileDesc = globalFD
}
fd = NewFileDescription(fileDesc, pbdb)
for _, enumValName := range fd.GetEnumNames() {
pbdb.revFileDescriptorMap[enumValName] = fd
}
for _, msgTypeName := range fd.GetTypeNames() {
pbdb.revFileDescriptorMap[msgTypeName] = fd
}
pbdb.revFileDescriptorMap[fileDesc.Path()] = fd
// Return the specific file descriptor registered.
pbdb.files = append(pbdb.files, fd)
return fd, nil
}
// RegisterMessage produces a `FileDescription` from a `message` and registers the message and all
// other definitions within the message file into the `pb.Db`.
func (pbdb *Db) RegisterMessage(message proto.Message) (*FileDescription, error) {
msgDesc := message.ProtoReflect().Descriptor()
msgName := msgDesc.FullName()
typeName := sanitizeProtoName(string(msgName))
if fd, found := pbdb.revFileDescriptorMap[typeName]; found {
return fd, nil
}
return pbdb.RegisterDescriptor(msgDesc.ParentFile())
}
// DescribeEnum takes a qualified enum name and returns an `EnumDescription` if it exists in the
// `pb.Db`.
func (pbdb *Db) DescribeEnum(enumName string) (*EnumValueDescription, bool) {
enumName = sanitizeProtoName(enumName)
if fd, found := pbdb.revFileDescriptorMap[enumName]; found {
return fd.GetEnumDescription(enumName)
}
return nil, false
}
// DescribeType returns a `TypeDescription` for the `typeName` if it exists in the `pb.Db`.
func (pbdb *Db) DescribeType(typeName string) (*TypeDescription, bool) {
typeName = sanitizeProtoName(typeName)
if fd, found := pbdb.revFileDescriptorMap[typeName]; found {
return fd.GetTypeDescription(typeName)
}
return nil, false
}
// CollectFileDescriptorSet builds a file descriptor set associated with the file where the input
// message is declared.
func CollectFileDescriptorSet(message proto.Message) map[string]protoreflect.FileDescriptor {
fdMap := map[string]protoreflect.FileDescriptor{}
parentFile := message.ProtoReflect().Descriptor().ParentFile()
fdMap[parentFile.Path()] = parentFile
// Initialize list of dependencies
deps := make([]protoreflect.FileImport, parentFile.Imports().Len())
for i := 0; i < parentFile.Imports().Len(); i++ {
deps[i] = parentFile.Imports().Get(i)
}
// Expand list for new dependencies
for i := 0; i < len(deps); i++ {
dep := deps[i]
if _, found := fdMap[dep.Path()]; found {
continue
}
fdMap[dep.Path()] = dep.FileDescriptor
for j := 0; j < dep.FileDescriptor.Imports().Len(); j++ {
deps = append(deps, dep.FileDescriptor.Imports().Get(j))
}
}
return fdMap
}
func init() {
// Describe well-known types to ensure they can always be resolved by the check and interpret
// execution phases.
//
// The following subset of message types is enough to ensure that all well-known types can
// resolved in the runtime, since describing the value results in describing the whole file
// where the message is declared.
DefaultDb.RegisterMessage(&anypb.Any{})
DefaultDb.RegisterMessage(&durpb.Duration{})
DefaultDb.RegisterMessage(&emptypb.Empty{})
DefaultDb.RegisterMessage(&tspb.Timestamp{})
DefaultDb.RegisterMessage(&structpb.Value{})
DefaultDb.RegisterMessage(&wrapperspb.BoolValue{})
}

552
vendor/github.com/google/cel-go/common/types/pb/type.go generated vendored Normal file
View File

@ -0,0 +1,552 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pb
import (
"fmt"
"reflect"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
dynamicpb "google.golang.org/protobuf/types/dynamicpb"
anypb "google.golang.org/protobuf/types/known/anypb"
dpb "google.golang.org/protobuf/types/known/durationpb"
structpb "google.golang.org/protobuf/types/known/structpb"
tpb "google.golang.org/protobuf/types/known/timestamppb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// description is a private interface used to make it convenient to perform type unwrapping at
// the TypeDescription or FieldDescription level.
type description interface {
// Zero returns an empty immutable protobuf message when the description is a protobuf message
// type.
Zero() proto.Message
}
// NewTypeDescription produces a TypeDescription value for the fully-qualified proto type name
// with a given descriptor.
func NewTypeDescription(typeName string, desc protoreflect.MessageDescriptor) *TypeDescription {
msgType := dynamicpb.NewMessageType(desc)
msgZero := dynamicpb.NewMessage(desc)
fieldMap := map[string]*FieldDescription{}
fields := desc.Fields()
for i := 0; i < fields.Len(); i++ {
f := fields.Get(i)
fieldMap[string(f.Name())] = NewFieldDescription(f)
}
return &TypeDescription{
typeName: typeName,
desc: desc,
msgType: msgType,
fieldMap: fieldMap,
reflectType: reflectTypeOf(msgZero),
zeroMsg: zeroValueOf(msgZero),
}
}
// TypeDescription is a collection of type metadata relevant to expression
// checking and evaluation.
type TypeDescription struct {
typeName string
desc protoreflect.MessageDescriptor
msgType protoreflect.MessageType
fieldMap map[string]*FieldDescription
reflectType reflect.Type
zeroMsg proto.Message
}
// FieldMap returns a string field name to FieldDescription map.
func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
return td.fieldMap
}
// FieldByName returns (FieldDescription, true) if the field name is declared within the type.
func (td *TypeDescription) FieldByName(name string) (*FieldDescription, bool) {
fd, found := td.fieldMap[name]
if !found {
return nil, false
}
return fd, true
}
// MaybeUnwrap accepts a proto message as input and unwraps it to a primitive CEL type if possible.
//
// This method returns the unwrapped value and 'true', else the original value and 'false'.
func (td *TypeDescription) MaybeUnwrap(msg proto.Message) (interface{}, bool, error) {
return unwrap(td, msg)
}
// Name returns the fully-qualified name of the type.
func (td *TypeDescription) Name() string {
return string(td.desc.FullName())
}
// New returns a mutable proto message
func (td *TypeDescription) New() protoreflect.Message {
return td.msgType.New()
}
// ReflectType returns the Golang reflect.Type for this type.
func (td *TypeDescription) ReflectType() reflect.Type {
return td.reflectType
}
// Zero returns the zero proto.Message value for this type.
func (td *TypeDescription) Zero() proto.Message {
return td.zeroMsg
}
// NewFieldDescription creates a new field description from a protoreflect.FieldDescriptor.
func NewFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescription {
var reflectType reflect.Type
var zeroMsg proto.Message
switch fieldDesc.Kind() {
case protoreflect.EnumKind:
reflectType = reflectTypeOf(protoreflect.EnumNumber(0))
case protoreflect.GroupKind, protoreflect.MessageKind:
zeroMsg = dynamicpb.NewMessage(fieldDesc.Message())
reflectType = reflectTypeOf(zeroMsg)
default:
reflectType = reflectTypeOf(fieldDesc.Default().Interface())
if fieldDesc.IsList() {
parentMsg := dynamicpb.NewMessage(fieldDesc.ContainingMessage())
listField := parentMsg.NewField(fieldDesc).List()
elem := listField.NewElement().Interface()
switch elemType := elem.(type) {
case protoreflect.Message:
elem = elemType.Interface()
}
reflectType = reflectTypeOf(elem)
}
}
// Ensure the list type is appropriately reflected as a Go-native list.
if fieldDesc.IsList() {
reflectType = reflect.SliceOf(reflectType)
}
var keyType, valType *FieldDescription
if fieldDesc.IsMap() {
keyType = NewFieldDescription(fieldDesc.MapKey())
valType = NewFieldDescription(fieldDesc.MapValue())
}
return &FieldDescription{
desc: fieldDesc,
KeyType: keyType,
ValueType: valType,
reflectType: reflectType,
zeroMsg: zeroValueOf(zeroMsg),
}
}
// FieldDescription holds metadata related to fields declared within a type.
type FieldDescription struct {
// KeyType holds the key FieldDescription for map fields.
KeyType *FieldDescription
// ValueType holds the value FieldDescription for map fields.
ValueType *FieldDescription
desc protoreflect.FieldDescriptor
reflectType reflect.Type
zeroMsg proto.Message
}
// CheckedType returns the type-definition used at type-check time.
func (fd *FieldDescription) CheckedType() *exprpb.Type {
if fd.desc.IsMap() {
return &exprpb.Type{
TypeKind: &exprpb.Type_MapType_{
MapType: &exprpb.Type_MapType{
KeyType: fd.KeyType.typeDefToType(),
ValueType: fd.ValueType.typeDefToType(),
},
},
}
}
if fd.desc.IsList() {
return &exprpb.Type{
TypeKind: &exprpb.Type_ListType_{
ListType: &exprpb.Type_ListType{
ElemType: fd.typeDefToType()}}}
}
return fd.typeDefToType()
}
// Descriptor returns the protoreflect.FieldDescriptor for this type.
func (fd *FieldDescription) Descriptor() protoreflect.FieldDescriptor {
return fd.desc
}
// IsSet returns whether the field is set on the target value, per the proto presence conventions
// of proto2 or proto3 accordingly.
//
// This function implements the FieldType.IsSet function contract which can be used to operate on
// more than just protobuf field accesses; however, the target here must be a protobuf.Message.
func (fd *FieldDescription) IsSet(target interface{}) bool {
switch v := target.(type) {
case proto.Message:
pbRef := v.ProtoReflect()
pbDesc := pbRef.Descriptor()
if pbDesc == fd.desc.ContainingMessage() {
// When the target protobuf shares the same message descriptor instance as the field
// descriptor, use the cached field descriptor value.
return pbRef.Has(fd.desc)
}
// Otherwise, fallback to a dynamic lookup of the field descriptor from the target
// instance as an attempt to use the cached field descriptor will result in a panic.
return pbRef.Has(pbDesc.Fields().ByName(protoreflect.Name(fd.Name())))
default:
return false
}
}
// GetFrom returns the accessor method associated with the field on the proto generated struct.
//
// If the field is not set, the proto default value is returned instead.
//
// This function implements the FieldType.GetFrom function contract which can be used to operate
// on more than just protobuf field accesses; however, the target here must be a protobuf.Message.
func (fd *FieldDescription) GetFrom(target interface{}) (interface{}, error) {
v, ok := target.(proto.Message)
if !ok {
return nil, fmt.Errorf("unsupported field selection target: (%T)%v", target, target)
}
pbRef := v.ProtoReflect()
pbDesc := pbRef.Descriptor()
var fieldVal interface{}
if pbDesc == fd.desc.ContainingMessage() {
// When the target protobuf shares the same message descriptor instance as the field
// descriptor, use the cached field descriptor value.
fieldVal = pbRef.Get(fd.desc).Interface()
} else {
// Otherwise, fallback to a dynamic lookup of the field descriptor from the target
// instance as an attempt to use the cached field descriptor will result in a panic.
fieldVal = pbRef.Get(pbDesc.Fields().ByName(protoreflect.Name(fd.Name()))).Interface()
}
switch fv := fieldVal.(type) {
// Fast-path return for primitive types.
case bool, []byte, float32, float64, int32, int64, string, uint32, uint64, protoreflect.List:
return fv, nil
case protoreflect.EnumNumber:
return int64(fv), nil
case protoreflect.Map:
// Return a wrapper around the protobuf-reflected Map types which carries additional
// information about the key and value definitions of the map.
return &Map{Map: fv, KeyType: fd.KeyType, ValueType: fd.ValueType}, nil
case protoreflect.Message:
// Make sure to unwrap well-known protobuf types before returning.
unwrapped, _, err := fd.MaybeUnwrapDynamic(fv)
return unwrapped, err
default:
return fv, nil
}
}
// IsEnum returns true if the field type refers to an enum value.
func (fd *FieldDescription) IsEnum() bool {
return fd.desc.Kind() == protoreflect.EnumKind
}
// IsMap returns true if the field is of map type.
func (fd *FieldDescription) IsMap() bool {
return fd.desc.IsMap()
}
// IsMessage returns true if the field is of message type.
func (fd *FieldDescription) IsMessage() bool {
kind := fd.desc.Kind()
return kind == protoreflect.MessageKind || kind == protoreflect.GroupKind
}
// IsOneof returns true if the field is declared within a oneof block.
func (fd *FieldDescription) IsOneof() bool {
return fd.desc.ContainingOneof() != nil
}
// IsList returns true if the field is a repeated value.
//
// This method will also return true for map values, so check whether the
// field is also a map.
func (fd *FieldDescription) IsList() bool {
return fd.desc.IsList()
}
// MaybeUnwrapDynamic takes the reflected protoreflect.Message and determines whether the
// value can be unwrapped to a more primitive CEL type.
//
// This function returns the unwrapped value and 'true' on success, or the original value
// and 'false' otherwise.
func (fd *FieldDescription) MaybeUnwrapDynamic(msg protoreflect.Message) (interface{}, bool, error) {
return unwrapDynamic(fd, msg)
}
// Name returns the CamelCase name of the field within the proto-based struct.
func (fd *FieldDescription) Name() string {
return string(fd.desc.Name())
}
// ReflectType returns the Golang reflect.Type for this field.
func (fd *FieldDescription) ReflectType() reflect.Type {
return fd.reflectType
}
// String returns the fully qualified name of the field within its type as well as whether the
// field occurs within a oneof.
func (fd *FieldDescription) String() string {
return fmt.Sprintf("%v.%s `oneof=%t`", fd.desc.ContainingMessage().FullName(), fd.Name(), fd.IsOneof())
}
// Zero returns the zero value for the protobuf message represented by this field.
//
// If the field is not a proto.Message type, the zero value is nil.
func (fd *FieldDescription) Zero() proto.Message {
return fd.zeroMsg
}
func (fd *FieldDescription) typeDefToType() *exprpb.Type {
if fd.desc.Kind() == protoreflect.MessageKind || fd.desc.Kind() == protoreflect.GroupKind {
msgType := string(fd.desc.Message().FullName())
if wk, found := CheckedWellKnowns[msgType]; found {
return wk
}
return checkedMessageType(msgType)
}
if fd.desc.Kind() == protoreflect.EnumKind {
return checkedInt
}
return CheckedPrimitives[fd.desc.Kind()]
}
// Map wraps the protoreflect.Map object with a key and value FieldDescription for use in
// retrieving individual elements within CEL value data types.
type Map struct {
protoreflect.Map
KeyType *FieldDescription
ValueType *FieldDescription
}
func checkedMessageType(name string) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_MessageType{MessageType: name}}
}
func checkedPrimitive(primitive exprpb.Type_PrimitiveType) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_Primitive{Primitive: primitive}}
}
func checkedWellKnown(wellKnown exprpb.Type_WellKnownType) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_WellKnown{WellKnown: wellKnown}}
}
func checkedWrap(t *exprpb.Type) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_Wrapper{Wrapper: t.GetPrimitive()}}
}
// unwrap unwraps the provided proto.Message value, potentially based on the description if the
// input message is a *dynamicpb.Message which obscures the typing information from Go.
//
// Returns the unwrapped value and 'true' if unwrapped, otherwise the input value and 'false'.
func unwrap(desc description, msg proto.Message) (interface{}, bool, error) {
switch v := msg.(type) {
case *anypb.Any:
dynMsg, err := v.UnmarshalNew()
if err != nil {
return v, false, err
}
return unwrapDynamic(desc, dynMsg.ProtoReflect())
case *dynamicpb.Message:
return unwrapDynamic(desc, v)
case *dpb.Duration:
return v.AsDuration(), true, nil
case *tpb.Timestamp:
return v.AsTime(), true, nil
case *structpb.Value:
switch v.GetKind().(type) {
case *structpb.Value_BoolValue:
return v.GetBoolValue(), true, nil
case *structpb.Value_ListValue:
return v.GetListValue(), true, nil
case *structpb.Value_NullValue:
return structpb.NullValue_NULL_VALUE, true, nil
case *structpb.Value_NumberValue:
return v.GetNumberValue(), true, nil
case *structpb.Value_StringValue:
return v.GetStringValue(), true, nil
case *structpb.Value_StructValue:
return v.GetStructValue(), true, nil
default:
return structpb.NullValue_NULL_VALUE, true, nil
}
case *wrapperspb.BoolValue:
return v.GetValue(), true, nil
case *wrapperspb.BytesValue:
return v.GetValue(), true, nil
case *wrapperspb.DoubleValue:
return v.GetValue(), true, nil
case *wrapperspb.FloatValue:
return float64(v.GetValue()), true, nil
case *wrapperspb.Int32Value:
return int64(v.GetValue()), true, nil
case *wrapperspb.Int64Value:
return v.GetValue(), true, nil
case *wrapperspb.StringValue:
return v.GetValue(), true, nil
case *wrapperspb.UInt32Value:
return uint64(v.GetValue()), true, nil
case *wrapperspb.UInt64Value:
return v.GetValue(), true, nil
}
return msg, false, nil
}
// unwrapDynamic unwraps a reflected protobuf Message value.
//
// Returns the unwrapped value and 'true' if unwrapped, otherwise the input value and 'false'.
func unwrapDynamic(desc description, refMsg protoreflect.Message) (interface{}, bool, error) {
msg := refMsg.Interface()
if !refMsg.IsValid() {
msg = desc.Zero()
}
// In order to ensure that these wrapped types match the expectations of the CEL type system
// the dynamicpb.Message must be merged with an protobuf instance of the well-known type value.
typeName := string(refMsg.Descriptor().FullName())
switch typeName {
case "google.protobuf.Any":
// Note, Any values require further unwrapping; however, this unwrapping may or may not
// be to a well-known type. If the unwrapped value is a well-known type it will be further
// unwrapped before being returned to the caller. Otherwise, the dynamic protobuf object
// represented by the Any will be returned.
unwrappedAny := &anypb.Any{}
err := Merge(unwrappedAny, msg)
if err != nil {
return nil, false, err
}
dynMsg, err := unwrappedAny.UnmarshalNew()
if err != nil {
// Allow the error to move further up the stack as it should result in an type
// conversion error if the caller does not recover it somehow.
return nil, false, err
}
// Attempt to unwrap the dynamic type, otherwise return the dynamic message.
unwrapped, nested, err := unwrapDynamic(desc, dynMsg.ProtoReflect())
if err == nil && nested {
return unwrapped, true, nil
}
return dynMsg, true, err
case "google.protobuf.BoolValue",
"google.protobuf.BytesValue",
"google.protobuf.DoubleValue",
"google.protobuf.FloatValue",
"google.protobuf.Int32Value",
"google.protobuf.Int64Value",
"google.protobuf.StringValue",
"google.protobuf.UInt32Value",
"google.protobuf.UInt64Value":
// The msg value is ignored when dealing with wrapper types as they have a null or value
// behavior, rather than the standard zero value behavior of other proto message types.
if !refMsg.IsValid() {
return structpb.NullValue_NULL_VALUE, true, nil
}
valueField := refMsg.Descriptor().Fields().ByName("value")
return refMsg.Get(valueField).Interface(), true, nil
case "google.protobuf.Duration":
unwrapped := &dpb.Duration{}
err := Merge(unwrapped, msg)
if err != nil {
return nil, false, err
}
return unwrapped.AsDuration(), true, nil
case "google.protobuf.ListValue":
unwrapped := &structpb.ListValue{}
err := Merge(unwrapped, msg)
if err != nil {
return nil, false, err
}
return unwrapped, true, nil
case "google.protobuf.NullValue":
return structpb.NullValue_NULL_VALUE, true, nil
case "google.protobuf.Struct":
unwrapped := &structpb.Struct{}
err := Merge(unwrapped, msg)
if err != nil {
return nil, false, err
}
return unwrapped, true, nil
case "google.protobuf.Timestamp":
unwrapped := &tpb.Timestamp{}
err := Merge(unwrapped, msg)
if err != nil {
return nil, false, err
}
return unwrapped.AsTime(), true, nil
case "google.protobuf.Value":
unwrapped := &structpb.Value{}
err := Merge(unwrapped, msg)
if err != nil {
return nil, false, err
}
return unwrap(desc, unwrapped)
}
return msg, false, nil
}
// reflectTypeOf intercepts the reflect.Type call to ensure that dynamicpb.Message types preserve
// well-known protobuf reflected types expected by the CEL type system.
func reflectTypeOf(val interface{}) reflect.Type {
switch v := val.(type) {
case proto.Message:
return reflect.TypeOf(zeroValueOf(v))
default:
return reflect.TypeOf(v)
}
}
// zeroValueOf will return the strongest possible proto.Message representing the default protobuf
// message value of the input msg type.
func zeroValueOf(msg proto.Message) proto.Message {
if msg == nil {
return nil
}
typeName := string(msg.ProtoReflect().Descriptor().FullName())
zeroVal, found := zeroValueMap[typeName]
if found {
return zeroVal
}
return msg
}
var (
zeroValueMap = map[string]proto.Message{
"google.protobuf.Any": &anypb.Any{},
"google.protobuf.Duration": &dpb.Duration{},
"google.protobuf.ListValue": &structpb.ListValue{},
"google.protobuf.Struct": &structpb.Struct{},
"google.protobuf.Timestamp": &tpb.Timestamp{},
"google.protobuf.Value": &structpb.Value{},
"google.protobuf.BoolValue": wrapperspb.Bool(false),
"google.protobuf.BytesValue": wrapperspb.Bytes([]byte{}),
"google.protobuf.DoubleValue": wrapperspb.Double(0.0),
"google.protobuf.FloatValue": wrapperspb.Float(0.0),
"google.protobuf.Int32Value": wrapperspb.Int32(0),
"google.protobuf.Int64Value": wrapperspb.Int64(0),
"google.protobuf.StringValue": wrapperspb.String(""),
"google.protobuf.UInt32Value": wrapperspb.UInt32(0),
"google.protobuf.UInt64Value": wrapperspb.UInt64(0),
}
)

View File

@ -0,0 +1,539 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"time"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
anypb "google.golang.org/protobuf/types/known/anypb"
dpb "google.golang.org/protobuf/types/known/durationpb"
structpb "google.golang.org/protobuf/types/known/structpb"
tpb "google.golang.org/protobuf/types/known/timestamppb"
)
type protoTypeRegistry struct {
revTypeMap map[string]ref.Type
pbdb *pb.Db
}
// NewRegistry accepts a list of proto message instances and returns a type
// provider which can create new instances of the provided message or any
// message that proto depends upon in its FileDescriptor.
func NewRegistry(types ...proto.Message) (ref.TypeRegistry, error) {
p := &protoTypeRegistry{
revTypeMap: make(map[string]ref.Type),
pbdb: pb.NewDb(),
}
err := p.RegisterType(
BoolType,
BytesType,
DoubleType,
DurationType,
IntType,
ListType,
MapType,
NullType,
StringType,
TimestampType,
TypeType,
UintType)
if err != nil {
return nil, err
}
// This block ensures that the well-known protobuf types are registered by default.
for _, fd := range p.pbdb.FileDescriptions() {
err = p.registerAllTypes(fd)
if err != nil {
return nil, err
}
}
for _, msgType := range types {
err = p.RegisterMessage(msgType)
if err != nil {
return nil, err
}
}
return p, nil
}
// NewEmptyRegistry returns a registry which is completely unconfigured.
func NewEmptyRegistry() ref.TypeRegistry {
return &protoTypeRegistry{
revTypeMap: make(map[string]ref.Type),
pbdb: pb.NewDb(),
}
}
// Copy implements the ref.TypeRegistry interface method which copies the current state of the
// registry into its own memory space.
func (p *protoTypeRegistry) Copy() ref.TypeRegistry {
copy := &protoTypeRegistry{
revTypeMap: make(map[string]ref.Type),
pbdb: p.pbdb.Copy(),
}
for k, v := range p.revTypeMap {
copy.revTypeMap[k] = v
}
return copy
}
func (p *protoTypeRegistry) EnumValue(enumName string) ref.Val {
enumVal, found := p.pbdb.DescribeEnum(enumName)
if !found {
return NewErr("unknown enum name '%s'", enumName)
}
return Int(enumVal.Value())
}
func (p *protoTypeRegistry) FindFieldType(messageType string,
fieldName string) (*ref.FieldType, bool) {
msgType, found := p.pbdb.DescribeType(messageType)
if !found {
return nil, false
}
field, found := msgType.FieldByName(fieldName)
if !found {
return nil, false
}
return &ref.FieldType{
Type: field.CheckedType(),
IsSet: field.IsSet,
GetFrom: field.GetFrom},
true
}
func (p *protoTypeRegistry) FindIdent(identName string) (ref.Val, bool) {
if t, found := p.revTypeMap[identName]; found {
return t.(ref.Val), true
}
if enumVal, found := p.pbdb.DescribeEnum(identName); found {
return Int(enumVal.Value()), true
}
return nil, false
}
func (p *protoTypeRegistry) FindType(typeName string) (*exprpb.Type, bool) {
if _, found := p.pbdb.DescribeType(typeName); !found {
return nil, false
}
if typeName != "" && typeName[0] == '.' {
typeName = typeName[1:]
}
return &exprpb.Type{
TypeKind: &exprpb.Type_Type{
Type: &exprpb.Type{
TypeKind: &exprpb.Type_MessageType{
MessageType: typeName}}}}, true
}
func (p *protoTypeRegistry) NewValue(typeName string, fields map[string]ref.Val) ref.Val {
td, found := p.pbdb.DescribeType(typeName)
if !found {
return NewErr("unknown type '%s'", typeName)
}
msg := td.New()
fieldMap := td.FieldMap()
for name, value := range fields {
field, found := fieldMap[name]
if !found {
return NewErr("no such field: %s", name)
}
err := msgSetField(msg, field, value)
if err != nil {
return &Err{err}
}
}
return p.NativeToValue(msg.Interface())
}
func (p *protoTypeRegistry) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) error {
fd, err := p.pbdb.RegisterDescriptor(fileDesc)
if err != nil {
return err
}
return p.registerAllTypes(fd)
}
func (p *protoTypeRegistry) RegisterMessage(message proto.Message) error {
fd, err := p.pbdb.RegisterMessage(message)
if err != nil {
return err
}
return p.registerAllTypes(fd)
}
func (p *protoTypeRegistry) RegisterType(types ...ref.Type) error {
for _, t := range types {
p.revTypeMap[t.TypeName()] = t
}
// TODO: generate an error when the type name is registered more than once.
return nil
}
// NativeToValue converts various "native" types to ref.Val with this specific implementation
// providing support for custom proto-based types.
//
// This method should be the inverse of ref.Val.ConvertToNative.
func (p *protoTypeRegistry) NativeToValue(value interface{}) ref.Val {
if val, found := nativeToValue(p, value); found {
return val
}
switch v := value.(type) {
case proto.Message:
typeName := string(v.ProtoReflect().Descriptor().FullName())
td, found := p.pbdb.DescribeType(typeName)
if !found {
return NewErr("unknown type: '%s'", typeName)
}
unwrapped, isUnwrapped, err := td.MaybeUnwrap(v)
if err != nil {
return UnsupportedRefValConversionErr(v)
}
if isUnwrapped {
return p.NativeToValue(unwrapped)
}
typeVal, found := p.FindIdent(typeName)
if !found {
return NewErr("unknown type: '%s'", typeName)
}
return NewObject(p, td, typeVal.(*TypeValue), v)
case *pb.Map:
return NewProtoMap(p, v)
case protoreflect.List:
return NewProtoList(p, v)
case protoreflect.Message:
return p.NativeToValue(v.Interface())
case protoreflect.Value:
return p.NativeToValue(v.Interface())
}
return UnsupportedRefValConversionErr(value)
}
func (p *protoTypeRegistry) registerAllTypes(fd *pb.FileDescription) error {
for _, typeName := range fd.GetTypeNames() {
err := p.RegisterType(NewObjectTypeValue(typeName))
if err != nil {
return err
}
}
return nil
}
// defaultTypeAdapter converts go native types to CEL values.
type defaultTypeAdapter struct{}
var (
// DefaultTypeAdapter adapts canonical CEL types from their equivalent Go values.
DefaultTypeAdapter = &defaultTypeAdapter{}
)
// NativeToValue implements the ref.TypeAdapter interface.
func (a *defaultTypeAdapter) NativeToValue(value interface{}) ref.Val {
if val, found := nativeToValue(a, value); found {
return val
}
return UnsupportedRefValConversionErr(value)
}
// nativeToValue returns the converted (ref.Val, true) of a conversion is found,
// otherwise (nil, false)
func nativeToValue(a ref.TypeAdapter, value interface{}) (ref.Val, bool) {
switch v := value.(type) {
case nil:
return NullValue, true
case *Bool:
if v != nil {
return *v, true
}
case *Bytes:
if v != nil {
return *v, true
}
case *Double:
if v != nil {
return *v, true
}
case *Int:
if v != nil {
return *v, true
}
case *String:
if v != nil {
return *v, true
}
case *Uint:
if v != nil {
return *v, true
}
case bool:
return Bool(v), true
case int:
return Int(v), true
case int32:
return Int(v), true
case int64:
return Int(v), true
case uint:
return Uint(v), true
case uint32:
return Uint(v), true
case uint64:
return Uint(v), true
case float32:
return Double(v), true
case float64:
return Double(v), true
case string:
return String(v), true
case *dpb.Duration:
return Duration{Duration: v.AsDuration()}, true
case time.Duration:
return Duration{Duration: v}, true
case *tpb.Timestamp:
return Timestamp{Time: v.AsTime()}, true
case time.Time:
return Timestamp{Time: v}, true
case *bool:
if v != nil {
return Bool(*v), true
}
case *float32:
if v != nil {
return Double(*v), true
}
case *float64:
if v != nil {
return Double(*v), true
}
case *int:
if v != nil {
return Int(*v), true
}
case *int32:
if v != nil {
return Int(*v), true
}
case *int64:
if v != nil {
return Int(*v), true
}
case *string:
if v != nil {
return String(*v), true
}
case *uint:
if v != nil {
return Uint(*v), true
}
case *uint32:
if v != nil {
return Uint(*v), true
}
case *uint64:
if v != nil {
return Uint(*v), true
}
case []byte:
return Bytes(v), true
// specializations for common lists types.
case []string:
return NewStringList(a, v), true
case []ref.Val:
return NewRefValList(a, v), true
// specializations for common map types.
case map[string]string:
return NewStringStringMap(a, v), true
case map[string]interface{}:
return NewStringInterfaceMap(a, v), true
case map[ref.Val]ref.Val:
return NewRefValMap(a, v), true
// additional specializations may be added upon request / need.
case *anypb.Any:
if v == nil {
return UnsupportedRefValConversionErr(v), true
}
unpackedAny, err := v.UnmarshalNew()
if err != nil {
return NewErr("anypb.UnmarshalNew() failed for type %q: %v", v.GetTypeUrl(), err), true
}
return a.NativeToValue(unpackedAny), true
case *structpb.NullValue, structpb.NullValue:
return NullValue, true
case *structpb.ListValue:
return NewJSONList(a, v), true
case *structpb.Struct:
return NewJSONStruct(a, v), true
case ref.Val:
return v, true
case protoreflect.EnumNumber:
return Int(v), true
case proto.Message:
if v == nil {
return UnsupportedRefValConversionErr(v), true
}
typeName := string(v.ProtoReflect().Descriptor().FullName())
td, found := pb.DefaultDb.DescribeType(typeName)
if !found {
return nil, false
}
val, unwrapped, err := td.MaybeUnwrap(v)
if err != nil {
return UnsupportedRefValConversionErr(v), true
}
if !unwrapped {
return nil, false
}
return a.NativeToValue(val), true
// Note: dynamicpb.Message implements the proto.Message _and_ protoreflect.Message interfaces
// which means that this case must appear after handling a proto.Message type.
case protoreflect.Message:
return a.NativeToValue(v.Interface()), true
default:
refValue := reflect.ValueOf(v)
if refValue.Kind() == reflect.Ptr {
if refValue.IsNil() {
return UnsupportedRefValConversionErr(v), true
}
refValue = refValue.Elem()
}
refKind := refValue.Kind()
switch refKind {
case reflect.Array, reflect.Slice:
return NewDynamicList(a, v), true
case reflect.Map:
return NewDynamicMap(a, v), true
// type aliases of primitive types cannot be asserted as that type, but rather need
// to be downcast to int32 before being converted to a CEL representation.
case reflect.Int32:
intType := reflect.TypeOf(int32(0))
return Int(refValue.Convert(intType).Interface().(int32)), true
case reflect.Int64:
intType := reflect.TypeOf(int64(0))
return Int(refValue.Convert(intType).Interface().(int64)), true
case reflect.Uint32:
uintType := reflect.TypeOf(uint32(0))
return Uint(refValue.Convert(uintType).Interface().(uint32)), true
case reflect.Uint64:
uintType := reflect.TypeOf(uint64(0))
return Uint(refValue.Convert(uintType).Interface().(uint64)), true
case reflect.Float32:
doubleType := reflect.TypeOf(float32(0))
return Double(refValue.Convert(doubleType).Interface().(float32)), true
case reflect.Float64:
doubleType := reflect.TypeOf(float64(0))
return Double(refValue.Convert(doubleType).Interface().(float64)), true
}
}
return nil, false
}
func msgSetField(target protoreflect.Message, field *pb.FieldDescription, val ref.Val) error {
if field.IsList() {
lv := target.NewField(field.Descriptor())
list, ok := val.(traits.Lister)
if !ok {
return unsupportedTypeConversionError(field, val)
}
err := msgSetListField(lv.List(), field, list)
if err != nil {
return err
}
target.Set(field.Descriptor(), lv)
return nil
}
if field.IsMap() {
mv := target.NewField(field.Descriptor())
mp, ok := val.(traits.Mapper)
if !ok {
return unsupportedTypeConversionError(field, val)
}
err := msgSetMapField(mv.Map(), field, mp)
if err != nil {
return err
}
target.Set(field.Descriptor(), mv)
return nil
}
v, err := val.ConvertToNative(field.ReflectType())
if err != nil {
return fieldTypeConversionError(field, err)
}
switch v.(type) {
case proto.Message:
v = v.(proto.Message).ProtoReflect()
}
target.Set(field.Descriptor(), protoreflect.ValueOf(v))
return nil
}
func msgSetListField(target protoreflect.List, listField *pb.FieldDescription, listVal traits.Lister) error {
elemReflectType := listField.ReflectType().Elem()
for i := Int(0); i < listVal.Size().(Int); i++ {
elem := listVal.Get(i)
elemVal, err := elem.ConvertToNative(elemReflectType)
if err != nil {
return fieldTypeConversionError(listField, err)
}
switch ev := elemVal.(type) {
case proto.Message:
elemVal = ev.ProtoReflect()
}
target.Append(protoreflect.ValueOf(elemVal))
}
return nil
}
func msgSetMapField(target protoreflect.Map, mapField *pb.FieldDescription, mapVal traits.Mapper) error {
targetKeyType := mapField.KeyType.ReflectType()
targetValType := mapField.ValueType.ReflectType()
it := mapVal.Iterator()
for it.HasNext() == True {
key := it.Next()
val := mapVal.Get(key)
k, err := key.ConvertToNative(targetKeyType)
if err != nil {
return fieldTypeConversionError(mapField, err)
}
v, err := val.ConvertToNative(targetValType)
if err != nil {
return fieldTypeConversionError(mapField, err)
}
switch v.(type) {
case proto.Message:
v = v.(proto.Message).ProtoReflect()
}
target.Set(protoreflect.ValueOf(k).MapKey(), protoreflect.ValueOf(v))
}
return nil
}
func unsupportedTypeConversionError(field *pb.FieldDescription, val ref.Val) error {
msgName := field.Descriptor().ContainingMessage().FullName()
return fmt.Errorf("unsupported field type for %v.%v: %v", msgName, field.Name(), val.Type())
}
func fieldTypeConversionError(field *pb.FieldDescription, err error) error {
msgName := field.Descriptor().ContainingMessage().FullName()
return fmt.Errorf("field type conversion error for %v.%v value type: %v", msgName, field.Name(), err)
}

View File

@ -0,0 +1,20 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"provider.go",
"reference.go",
],
importpath = "github.com/google/cel-go/common/types/ref",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
],
)

View File

@ -0,0 +1,103 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ref
import (
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// TypeProvider specifies functions for creating new object instances and for
// resolving enum values by name.
type TypeProvider interface {
// EnumValue returns the numeric value of the given enum value name.
EnumValue(enumName string) Val
// FindIdent takes a qualified identifier name and returns a Value if one
// exists.
FindIdent(identName string) (Val, bool)
// FindType looks up the Type given a qualified typeName. Returns false
// if not found.
//
// Used during type-checking only.
FindType(typeName string) (*exprpb.Type, bool)
// FieldFieldType returns the field type for a checked type value. Returns
// false if the field could not be found.
//
// Used during type-checking only.
FindFieldType(messageType string, fieldName string) (*FieldType, bool)
// NewValue creates a new type value from a qualified name and map of field
// name to value.
//
// Note, for each value, the Val.ConvertToNative function will be invoked
// to convert the Val to the field's native type. If an error occurs during
// conversion, the NewValue will be a types.Err.
NewValue(typeName string, fields map[string]Val) Val
}
// TypeAdapter converts native Go values of varying type and complexity to equivalent CEL values.
type TypeAdapter interface {
// NativeToValue converts the input `value` to a CEL `ref.Val`.
NativeToValue(value interface{}) Val
}
// TypeRegistry allows third-parties to add custom types to CEL. Not all `TypeProvider`
// implementations support type-customization, so these features are optional. However, a
// `TypeRegistry` should be a `TypeProvider` and a `TypeAdapter` to ensure that types
// which are registered can be converted to CEL representations.
type TypeRegistry interface {
TypeAdapter
TypeProvider
// RegisterDescriptor registers the contents of a protocol buffer `FileDescriptor`.
RegisterDescriptor(fileDesc protoreflect.FileDescriptor) error
// RegisterMessage registers a protocol buffer message and its dependencies.
RegisterMessage(message proto.Message) error
// RegisterType registers a type value with the provider which ensures the
// provider is aware of how to map the type to an identifier.
//
// If a type is provided more than once with an alternative definition, the
// call will result in an error.
RegisterType(types ...Type) error
// Copy the TypeRegistry and return a new registry whose mutable state is isolated.
Copy() TypeRegistry
}
// FieldType represents a field's type value and whether that field supports
// presence detection.
type FieldType struct {
// Type of the field.
Type *exprpb.Type
// IsSet indicates whether the field is set on an input object.
IsSet FieldTester
// GetFrom retrieves the field value on the input object, if set.
GetFrom FieldGetter
}
// FieldTester is used to test field presence on an input object.
type FieldTester func(target interface{}) bool
// FieldGetter is used to get the field value from an input object, if set.
type FieldGetter func(target interface{}) (interface{}, error)

View File

@ -0,0 +1,54 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package ref contains the reference interfaces used throughout the types components.
package ref
import (
"reflect"
)
// Type interface indicate the name of a given type.
type Type interface {
// HasTrait returns whether the type has a given trait associated with it.
//
// See common/types/traits/traits.go for a list of supported traits.
HasTrait(trait int) bool
// TypeName returns the qualified type name of the type.
//
// The type name is also used as the type's identifier name at type-check and interpretation time.
TypeName() string
}
// Val interface defines the functions supported by all expression values.
// Val implementations may specialize the behavior of the value through the addition of traits.
type Val interface {
// ConvertToNative converts the Value to a native Go struct according to the
// reflected type description, or error if the conversion is not feasible.
ConvertToNative(typeDesc reflect.Type) (interface{}, error)
// ConvertToType supports type conversions between value types supported by the expression language.
ConvertToType(typeValue Type) Val
// Equal returns true if the `other` value has the same type and content as the implementing struct.
Equal(other Val) Val
// Type returns the TypeValue of the value.
Type() Type
// Value returns the raw value of the instance which may not be directly compatible with the expression
// language types.
Value() interface{}
}

218
vendor/github.com/google/cel-go/common/types/string.go generated vendored Normal file
View File

@ -0,0 +1,218 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/google/cel-go/common/overloads"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// String type implementation which supports addition, comparison, matching,
// and size functions.
type String string
var (
// StringType singleton.
StringType = NewTypeValue("string",
traits.AdderType,
traits.ComparerType,
traits.MatcherType,
traits.ReceiverType,
traits.SizerType)
stringOneArgOverloads = map[string]func(String, ref.Val) ref.Val{
overloads.Contains: stringContains,
overloads.EndsWith: stringEndsWith,
overloads.StartsWith: stringStartsWith,
}
stringWrapperType = reflect.TypeOf(&wrapperspb.StringValue{})
)
// Add implements traits.Adder.Add.
func (s String) Add(other ref.Val) ref.Val {
otherString, ok := other.(String)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return s + otherString
}
// Compare implements traits.Comparer.Compare.
func (s String) Compare(other ref.Val) ref.Val {
otherString, ok := other.(String)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return Int(strings.Compare(s.Value().(string), otherString.Value().(string)))
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (s String) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.String:
if reflect.TypeOf(s).AssignableTo(typeDesc) {
return s, nil
}
return s.Value(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.String(string(s)))
case jsonValueType:
// Convert to a protobuf representation of a JSON String.
return structpb.NewStringValue(string(s)), nil
case stringWrapperType:
// Convert to a wrapperspb.StringValue.
return wrapperspb.String(string(s)), nil
}
if typeDesc.Elem().Kind() == reflect.String {
p := s.Value().(string)
return &p, nil
}
case reflect.Interface:
sv := s.Value()
if reflect.TypeOf(sv).Implements(typeDesc) {
return sv, nil
}
if reflect.TypeOf(s).Implements(typeDesc) {
return s, nil
}
}
return nil, fmt.Errorf(
"unsupported native conversion from string to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (s String) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
if n, err := strconv.ParseInt(s.Value().(string), 10, 64); err == nil {
return Int(n)
}
case UintType:
if n, err := strconv.ParseUint(s.Value().(string), 10, 64); err == nil {
return Uint(n)
}
case DoubleType:
if n, err := strconv.ParseFloat(s.Value().(string), 64); err == nil {
return Double(n)
}
case BoolType:
if b, err := strconv.ParseBool(s.Value().(string)); err == nil {
return Bool(b)
}
case BytesType:
return Bytes(s)
case DurationType:
if d, err := time.ParseDuration(s.Value().(string)); err == nil {
return durationOf(d)
}
case TimestampType:
if t, err := time.Parse(time.RFC3339, s.Value().(string)); err == nil {
if t.Unix() < minUnixTime || t.Unix() > maxUnixTime {
return celErrTimestampOverflow
}
return timestampOf(t)
}
case StringType:
return s
case TypeType:
return StringType
}
return NewErr("type conversion error from '%s' to '%s'", StringType, typeVal)
}
// Equal implements ref.Val.Equal.
func (s String) Equal(other ref.Val) ref.Val {
otherString, ok := other.(String)
return Bool(ok && s == otherString)
}
// Match implements traits.Matcher.Match.
func (s String) Match(pattern ref.Val) ref.Val {
pat, ok := pattern.(String)
if !ok {
return MaybeNoSuchOverloadErr(pattern)
}
matched, err := regexp.MatchString(pat.Value().(string), s.Value().(string))
if err != nil {
return &Err{err}
}
return Bool(matched)
}
// Receive implements traits.Receiver.Receive.
func (s String) Receive(function string, overload string, args []ref.Val) ref.Val {
switch len(args) {
case 1:
if f, found := stringOneArgOverloads[function]; found {
return f(s, args[0])
}
}
return NoSuchOverloadErr()
}
// Size implements traits.Sizer.Size.
func (s String) Size() ref.Val {
return Int(len([]rune(s.Value().(string))))
}
// Type implements ref.Val.Type.
func (s String) Type() ref.Type {
return StringType
}
// Value implements ref.Val.Value.
func (s String) Value() interface{} {
return string(s)
}
func stringContains(s String, sub ref.Val) ref.Val {
subStr, ok := sub.(String)
if !ok {
return MaybeNoSuchOverloadErr(sub)
}
return Bool(strings.Contains(string(s), string(subStr)))
}
func stringEndsWith(s String, suf ref.Val) ref.Val {
sufStr, ok := suf.(String)
if !ok {
return MaybeNoSuchOverloadErr(suf)
}
return Bool(strings.HasSuffix(string(s), string(sufStr)))
}
func stringStartsWith(s String, pre ref.Val) ref.Val {
preStr, ok := pre.(String)
if !ok {
return MaybeNoSuchOverloadErr(pre)
}
return Bool(strings.HasPrefix(string(s), string(preStr)))
}

View File

@ -0,0 +1,316 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/google/cel-go/common/overloads"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
tpb "google.golang.org/protobuf/types/known/timestamppb"
)
// Timestamp type implementation which supports add, compare, and subtract
// operations. Timestamps are also capable of participating in dynamic
// function dispatch to instance methods.
type Timestamp struct {
time.Time
}
func timestampOf(t time.Time) Timestamp {
// Note that this function does not validate that time.Time is in our supported range.
return Timestamp{Time: t}
}
const (
// The number of seconds between year 1 and year 1970. This is borrowed from
// https://golang.org/src/time/time.go.
unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * (60 * 60 * 24)
// Number of seconds between `0001-01-01T00:00:00Z` and the Unix epoch.
minUnixTime int64 = -62135596800
// Number of seconds between `9999-12-31T23:59:59.999999999Z` and the Unix epoch.
maxUnixTime int64 = 253402300799
)
var (
// TimestampType singleton.
TimestampType = NewTypeValue("google.protobuf.Timestamp",
traits.AdderType,
traits.ComparerType,
traits.ReceiverType,
traits.SubtractorType)
)
// Add implements traits.Adder.Add.
func (t Timestamp) Add(other ref.Val) ref.Val {
switch other.Type() {
case DurationType:
return other.(Duration).Add(t)
}
return MaybeNoSuchOverloadErr(other)
}
// Compare implements traits.Comparer.Compare.
func (t Timestamp) Compare(other ref.Val) ref.Val {
if TimestampType != other.Type() {
return MaybeNoSuchOverloadErr(other)
}
ts1 := t.Time
ts2 := other.(Timestamp).Time
switch {
case ts1.Before(ts2):
return IntNegOne
case ts1.After(ts2):
return IntOne
default:
return IntZero
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (t Timestamp) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the timestamp is already assignable to the desired type return it.
if reflect.TypeOf(t.Time).AssignableTo(typeDesc) {
return t.Time, nil
}
if reflect.TypeOf(t).AssignableTo(typeDesc) {
return t, nil
}
switch typeDesc {
case anyValueType:
// Pack the underlying time as a tpb.Timestamp into an Any value.
return anypb.New(tpb.New(t.Time))
case jsonValueType:
// CEL follows the proto3 to JSON conversion which formats as an RFC 3339 encoded JSON
// string.
v := t.ConvertToType(StringType)
if IsError(v) {
return nil, v.(*Err)
}
return structpb.NewStringValue(string(v.(String))), nil
case timestampValueType:
// Unwrap the underlying tpb.Timestamp.
return tpb.New(t.Time), nil
}
return nil, fmt.Errorf("type conversion error from 'Timestamp' to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (t Timestamp) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String(t.Format(time.RFC3339Nano))
case IntType:
// Return the Unix time in seconds since 1970
return Int(t.Unix())
case TimestampType:
return t
case TypeType:
return TimestampType
}
return NewErr("type conversion error from '%s' to '%s'", TimestampType, typeVal)
}
// Equal implements ref.Val.Equal.
func (t Timestamp) Equal(other ref.Val) ref.Val {
otherTime, ok := other.(Timestamp)
return Bool(ok && t.Time.Equal(otherTime.Time))
}
// Receive implements traits.Receiver.Receive.
func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref.Val {
switch len(args) {
case 0:
if f, found := timestampZeroArgOverloads[function]; found {
return f(t.Time)
}
case 1:
if f, found := timestampOneArgOverloads[function]; found {
return f(t.Time, args[0])
}
}
return NoSuchOverloadErr()
}
// Subtract implements traits.Subtractor.Subtract.
func (t Timestamp) Subtract(subtrahend ref.Val) ref.Val {
switch subtrahend.Type() {
case DurationType:
dur := subtrahend.(Duration)
val, err := subtractTimeDurationChecked(t.Time, dur.Duration)
if err != nil {
return wrapErr(err)
}
return timestampOf(val)
case TimestampType:
t2 := subtrahend.(Timestamp).Time
val, err := subtractTimeChecked(t.Time, t2)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
}
return MaybeNoSuchOverloadErr(subtrahend)
}
// Type implements ref.Val.Type.
func (t Timestamp) Type() ref.Type {
return TimestampType
}
// Value implements ref.Val.Value.
func (t Timestamp) Value() interface{} {
return t.Time
}
var (
timestampValueType = reflect.TypeOf(&tpb.Timestamp{})
timestampZeroArgOverloads = map[string]func(time.Time) ref.Val{
overloads.TimeGetFullYear: timestampGetFullYear,
overloads.TimeGetMonth: timestampGetMonth,
overloads.TimeGetDayOfYear: timestampGetDayOfYear,
overloads.TimeGetDate: timestampGetDayOfMonthOneBased,
overloads.TimeGetDayOfMonth: timestampGetDayOfMonthZeroBased,
overloads.TimeGetDayOfWeek: timestampGetDayOfWeek,
overloads.TimeGetHours: timestampGetHours,
overloads.TimeGetMinutes: timestampGetMinutes,
overloads.TimeGetSeconds: timestampGetSeconds,
overloads.TimeGetMilliseconds: timestampGetMilliseconds}
timestampOneArgOverloads = map[string]func(time.Time, ref.Val) ref.Val{
overloads.TimeGetFullYear: timestampGetFullYearWithTz,
overloads.TimeGetMonth: timestampGetMonthWithTz,
overloads.TimeGetDayOfYear: timestampGetDayOfYearWithTz,
overloads.TimeGetDate: timestampGetDayOfMonthOneBasedWithTz,
overloads.TimeGetDayOfMonth: timestampGetDayOfMonthZeroBasedWithTz,
overloads.TimeGetDayOfWeek: timestampGetDayOfWeekWithTz,
overloads.TimeGetHours: timestampGetHoursWithTz,
overloads.TimeGetMinutes: timestampGetMinutesWithTz,
overloads.TimeGetSeconds: timestampGetSecondsWithTz,
overloads.TimeGetMilliseconds: timestampGetMillisecondsWithTz}
)
type timestampVisitor func(time.Time) ref.Val
func timestampGetFullYear(t time.Time) ref.Val {
return Int(t.Year())
}
func timestampGetMonth(t time.Time) ref.Val {
// CEL spec indicates that the month should be 0-based, but the Time value
// for Month() is 1-based.
return Int(t.Month() - 1)
}
func timestampGetDayOfYear(t time.Time) ref.Val {
return Int(t.YearDay() - 1)
}
func timestampGetDayOfMonthZeroBased(t time.Time) ref.Val {
return Int(t.Day() - 1)
}
func timestampGetDayOfMonthOneBased(t time.Time) ref.Val {
return Int(t.Day())
}
func timestampGetDayOfWeek(t time.Time) ref.Val {
return Int(t.Weekday())
}
func timestampGetHours(t time.Time) ref.Val {
return Int(t.Hour())
}
func timestampGetMinutes(t time.Time) ref.Val {
return Int(t.Minute())
}
func timestampGetSeconds(t time.Time) ref.Val {
return Int(t.Second())
}
func timestampGetMilliseconds(t time.Time) ref.Val {
return Int(t.Nanosecond() / 1000000)
}
func timestampGetFullYearWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetFullYear)(t)
}
func timestampGetMonthWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetMonth)(t)
}
func timestampGetDayOfYearWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetDayOfYear)(t)
}
func timestampGetDayOfMonthZeroBasedWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetDayOfMonthZeroBased)(t)
}
func timestampGetDayOfMonthOneBasedWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetDayOfMonthOneBased)(t)
}
func timestampGetDayOfWeekWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetDayOfWeek)(t)
}
func timestampGetHoursWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetHours)(t)
}
func timestampGetMinutesWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetMinutes)(t)
}
func timestampGetSecondsWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetSeconds)(t)
}
func timestampGetMillisecondsWithTz(t time.Time, tz ref.Val) ref.Val {
return timeZone(tz, timestampGetMilliseconds)(t)
}
func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor {
return func(t time.Time) ref.Val {
if StringType != tz.Type() {
return MaybeNoSuchOverloadErr(tz)
}
val := string(tz.(String))
ind := strings.Index(val, ":")
if ind == -1 {
loc, err := time.LoadLocation(val)
if err != nil {
return wrapErr(err)
}
return visitor(t.In(loc))
}
// If the input is not the name of a timezone (for example, 'US/Central'), it should be a numerical offset from UTC
// in the format ^(+|-)(0[0-9]|1[0-4]):[0-5][0-9]$. The numerical input is parsed in terms of hours and minutes.
hr, err := strconv.Atoi(string(val[0:ind]))
if err != nil {
return wrapErr(err)
}
min, err := strconv.Atoi(string(val[ind+1:]))
if err != nil {
return wrapErr(err)
}
var offset int
if string(val[0]) == "-" {
offset = hr*60 - min
} else {
offset = hr*60 + min
}
secondsEastOfUTC := int((time.Duration(offset) * time.Minute).Seconds())
timezone := time.FixedZone("", secondsEastOfUTC)
return visitor(t.In(timezone))
}
}

View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"comparer.go",
"container.go",
"field_tester.go",
"indexer.go",
"iterator.go",
"lister.go",
"mapper.go",
"matcher.go",
"math.go",
"receiver.go",
"sizer.go",
"traits.go",
],
importpath = "github.com/google/cel-go/common/types/traits",
deps = [
"//common/types/ref:go_default_library",
],
)

View File

@ -0,0 +1,33 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import (
"github.com/google/cel-go/common/types/ref"
)
// Comparer interface for ordering comparisons between values in order to
// support '<', '<=', '>=', '>' overloads.
type Comparer interface {
// Compare this value to the input other value, returning an Int:
//
// this < other -> Int(-1)
// this == other -> Int(0)
// this > other -> Int(1)
//
// If the comparison cannot be made or is not supported, an error should
// be returned.
Compare(other ref.Val) ref.Val
}

View File

@ -0,0 +1,23 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Container interface which permits containment tests such as 'a in b'.
type Container interface {
// Contains returns true if the value exists within the object.
Contains(value ref.Val) ref.Val
}

View File

@ -0,0 +1,30 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import (
"github.com/google/cel-go/common/types/ref"
)
// FieldTester indicates if a defined field on an object type is set to a
// non-default value.
//
// For use with the `has()` macro.
type FieldTester interface {
// IsSet returns true if the field is defined and set to a non-default
// value. The method will return false if defined and not set, and an error
// if the field is not defined.
IsSet(field ref.Val) ref.Val
}

View File

@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import (
"github.com/google/cel-go/common/types/ref"
)
// Indexer permits random access of elements by index 'a[b()]'.
type Indexer interface {
// Get the value at the specified index or error.
Get(index ref.Val) ref.Val
}

View File

@ -0,0 +1,36 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import (
"github.com/google/cel-go/common/types/ref"
)
// Iterable aggregate types permit traversal over their elements.
type Iterable interface {
// Iterator returns a new iterator view of the struct.
Iterator() Iterator
}
// Iterator permits safe traversal over the contents of an aggregate type.
type Iterator interface {
ref.Val
// HasNext returns true if there are unvisited elements in the Iterator.
HasNext() ref.Val
// Next returns the next element.
Next() ref.Val
}

View File

@ -0,0 +1,33 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Lister interface which aggregates the traits of a list.
type Lister interface {
ref.Val
Adder
Container
Indexer
Iterable
Sizer
}
// MutableLister interface which emits an immutable result after an intermediate computation.
type MutableLister interface {
Lister
ToImmutableList() Lister
}

View File

@ -0,0 +1,33 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Mapper interface which aggregates the traits of a maps.
type Mapper interface {
ref.Val
Container
Indexer
Iterable
Sizer
// Find returns a value, if one exists, for the input key.
//
// If the key is not found the function returns (nil, false).
// If the input key is not valid for the map, or is Err or Unknown the function returns
// (Unknown|Err, false).
Find(key ref.Val) (ref.Val, bool)
}

View File

@ -0,0 +1,23 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Matcher interface for supporting 'matches()' overloads.
type Matcher interface {
// Match returns true if the pattern matches the current value.
Match(pattern ref.Val) ref.Val
}

View File

@ -0,0 +1,62 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Adder interface to support '+' operator overloads.
type Adder interface {
// Add returns a combination of the current value and other value.
//
// If the other value is an unsupported type, an error is returned.
Add(other ref.Val) ref.Val
}
// Divider interface to support '/' operator overloads.
type Divider interface {
// Divide returns the result of dividing the current value by the input
// denominator.
//
// A denominator value of zero results in an error.
Divide(denominator ref.Val) ref.Val
}
// Modder interface to support '%' operator overloads.
type Modder interface {
// Modulo returns the result of taking the modulus of the current value
// by the denominator.
//
// A denominator value of zero results in an error.
Modulo(denominator ref.Val) ref.Val
}
// Multiplier interface to support '*' operator overloads.
type Multiplier interface {
// Multiply returns the result of multiplying the current and input value.
Multiply(other ref.Val) ref.Val
}
// Negater interface to support unary '-' and '!' operator overloads.
type Negater interface {
// Negate returns the complement of the current value.
Negate() ref.Val
}
// Subtractor interface to support binary '-' operator overloads.
type Subtractor interface {
// Subtract returns the result of subtracting the input from the current
// value.
Subtract(subtrahend ref.Val) ref.Val
}

View File

@ -0,0 +1,24 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import "github.com/google/cel-go/common/types/ref"
// Receiver interface for routing instance method calls within a value.
type Receiver interface {
// Receive accepts a function name, overload id, and arguments and returns
// a value.
Receive(function string, overload string, args []ref.Val) ref.Val
}

View File

@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package traits
import (
"github.com/google/cel-go/common/types/ref"
)
// Sizer interface for supporting 'size()' overloads.
type Sizer interface {
// Size returns the number of elements or length of the value.
Size() ref.Val
}

View File

@ -0,0 +1,64 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package traits defines interfaces that a type may implement to participate
// in operator overloads and function dispatch.
package traits
const (
// AdderType types provide a '+' operator overload.
AdderType = 1 << iota
// ComparerType types support ordering comparisons '<', '<=', '>', '>='.
ComparerType
// ContainerType types support 'in' operations.
ContainerType
// DividerType types support '/' operations.
DividerType
// FieldTesterType types support the detection of field value presence.
FieldTesterType
// IndexerType types support index access with dynamic values.
IndexerType
// IterableType types can be iterated over in comprehensions.
IterableType
// IteratorType types support iterator semantics.
IteratorType
// MatcherType types support pattern matching via 'matches' method.
MatcherType
// ModderType types support modulus operations '%'
ModderType
// MultiplierType types support '*' operations.
MultiplierType
// NegatorType types support either negation via '!' or '-'
NegatorType
// ReceiverType types support dynamic dispatch to instance methods.
ReceiverType
// SizerType types support the size() method.
SizerType
// SubtractorType type support '-' operations.
SubtractorType
)

102
vendor/github.com/google/cel-go/common/types/type.go generated vendored Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var (
// TypeType is the type of a TypeValue.
TypeType = NewTypeValue("type")
)
// TypeValue is an instance of a Value that describes a value's type.
type TypeValue struct {
name string
traitMask int
}
// NewTypeValue returns *TypeValue which is both a ref.Type and ref.Val.
func NewTypeValue(name string, traits ...int) *TypeValue {
traitMask := 0
for _, trait := range traits {
traitMask |= trait
}
return &TypeValue{
name: name,
traitMask: traitMask}
}
// NewObjectTypeValue returns a *TypeValue based on the input name, which is
// annotated with the traits relevant to all objects.
func NewObjectTypeValue(name string) *TypeValue {
return NewTypeValue(name,
traits.FieldTesterType,
traits.IndexerType)
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (t *TypeValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// TODO: replace the internal type representation with a proto-value.
return nil, fmt.Errorf("type conversion not supported for 'type'")
}
// ConvertToType implements ref.Val.ConvertToType.
func (t *TypeValue) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case TypeType:
return TypeType
case StringType:
return String(t.TypeName())
}
return NewErr("type conversion error from '%s' to '%s'", TypeType, typeVal)
}
// Equal implements ref.Val.Equal.
func (t *TypeValue) Equal(other ref.Val) ref.Val {
otherType, ok := other.(ref.Type)
return Bool(ok && t.TypeName() == otherType.TypeName())
}
// HasTrait indicates whether the type supports the given trait.
// Trait codes are defined in the traits package, e.g. see traits.AdderType.
func (t *TypeValue) HasTrait(trait int) bool {
return trait&t.traitMask == trait
}
// String implements fmt.Stringer.
func (t *TypeValue) String() string {
return t.name
}
// Type implements ref.Val.Type.
func (t *TypeValue) Type() ref.Type {
return TypeType
}
// TypeName gives the type's name as a string.
func (t *TypeValue) TypeName() string {
return t.name
}
// Value implements ref.Val.Value.
func (t *TypeValue) Value() interface{} {
return t.name
}

249
vendor/github.com/google/cel-go/common/types/uint.go generated vendored Normal file
View File

@ -0,0 +1,249 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"fmt"
"math"
"reflect"
"strconv"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Uint type implementation which supports comparison and math operators.
type Uint uint64
var (
// UintType singleton.
UintType = NewTypeValue("uint",
traits.AdderType,
traits.ComparerType,
traits.DividerType,
traits.ModderType,
traits.MultiplierType,
traits.SubtractorType)
uint32WrapperType = reflect.TypeOf(&wrapperspb.UInt32Value{})
uint64WrapperType = reflect.TypeOf(&wrapperspb.UInt64Value{})
)
// Uint constants
const (
uintZero = Uint(0)
)
// Add implements traits.Adder.Add.
func (i Uint) Add(other ref.Val) ref.Val {
otherUint, ok := other.(Uint)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := addUint64Checked(uint64(i), uint64(otherUint))
if err != nil {
return wrapErr(err)
}
return Uint(val)
}
// Compare implements traits.Comparer.Compare.
func (i Uint) Compare(other ref.Val) ref.Val {
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return NewErr("NaN values cannot be ordered")
}
return compareUintDouble(i, ov)
case Int:
return compareUintInt(i, ov)
case Uint:
return compareUint(i, ov)
default:
return MaybeNoSuchOverloadErr(other)
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Uint, reflect.Uint32:
v, err := uint64ToUint32Checked(uint64(i))
if err != nil {
return 0, err
}
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Uint64:
return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.UInt64(uint64(i)))
case jsonValueType:
// JSON can accurately represent 32-bit uints as floating point values.
if i.isJSONSafe() {
return structpb.NewNumberValue(float64(i)), nil
}
// Proto3 to JSON conversion requires string-formatted uint64 values
// since the conversion to floating point would result in truncation.
return structpb.NewStringValue(strconv.FormatUint(uint64(i), 10)), nil
case uint32WrapperType:
// Convert the value to a wrapperspb.UInt32Value, error on overflow.
v, err := uint64ToUint32Checked(uint64(i))
if err != nil {
return 0, err
}
return wrapperspb.UInt32(v), nil
case uint64WrapperType:
// Convert the value to a wrapperspb.UInt64Value.
return wrapperspb.UInt64(uint64(i)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Uint32:
v, err := uint64ToUint32Checked(uint64(i))
if err != nil {
return 0, err
}
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Uint64:
v := uint64(i)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
iv := i.Value()
if reflect.TypeOf(iv).Implements(typeDesc) {
return iv, nil
}
if reflect.TypeOf(i).Implements(typeDesc) {
return i, nil
}
}
return nil, fmt.Errorf("unsupported type conversion from 'uint' to %v", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (i Uint) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
v, err := uint64ToInt64Checked(uint64(i))
if err != nil {
return wrapErr(err)
}
return Int(v)
case UintType:
return i
case DoubleType:
return Double(i)
case StringType:
return String(fmt.Sprintf("%d", uint64(i)))
case TypeType:
return UintType
}
return NewErr("type conversion error from '%s' to '%s'", UintType, typeVal)
}
// Divide implements traits.Divider.Divide.
func (i Uint) Divide(other ref.Val) ref.Val {
otherUint, ok := other.(Uint)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
div, err := divideUint64Checked(uint64(i), uint64(otherUint))
if err != nil {
return wrapErr(err)
}
return Uint(div)
}
// Equal implements ref.Val.Equal.
func (i Uint) Equal(other ref.Val) ref.Val {
switch ov := other.(type) {
case Double:
if math.IsNaN(float64(ov)) {
return False
}
return Bool(compareUintDouble(i, ov) == 0)
case Int:
return Bool(compareUintInt(i, ov) == 0)
case Uint:
return Bool(i == ov)
default:
return False
}
}
// Modulo implements traits.Modder.Modulo.
func (i Uint) Modulo(other ref.Val) ref.Val {
otherUint, ok := other.(Uint)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
mod, err := moduloUint64Checked(uint64(i), uint64(otherUint))
if err != nil {
return wrapErr(err)
}
return Uint(mod)
}
// Multiply implements traits.Multiplier.Multiply.
func (i Uint) Multiply(other ref.Val) ref.Val {
otherUint, ok := other.(Uint)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := multiplyUint64Checked(uint64(i), uint64(otherUint))
if err != nil {
return wrapErr(err)
}
return Uint(val)
}
// Subtract implements traits.Subtractor.Subtract.
func (i Uint) Subtract(subtrahend ref.Val) ref.Val {
subtraUint, ok := subtrahend.(Uint)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
val, err := subtractUint64Checked(uint64(i), uint64(subtraUint))
if err != nil {
return wrapErr(err)
}
return Uint(val)
}
// Type implements ref.Val.Type.
func (i Uint) Type() ref.Type {
return UintType
}
// Value implements ref.Val.Value.
func (i Uint) Value() interface{} {
return uint64(i)
}
// isJSONSafe indicates whether the uint is safely representable as a floating point value in JSON.
func (i Uint) isJSONSafe() bool {
return i <= maxIntJSON
}

View File

@ -0,0 +1,66 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"reflect"
"github.com/google/cel-go/common/types/ref"
)
// Unknown type implementation which collects expression ids which caused the
// current value to become unknown.
type Unknown []int64
var (
// UnknownType singleton.
UnknownType = NewTypeValue("unknown")
)
// ConvertToNative implements ref.Val.ConvertToNative.
func (u Unknown) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
return u.Value(), nil
}
// ConvertToType is an identity function since unknown values cannot be modified.
func (u Unknown) ConvertToType(typeVal ref.Type) ref.Val {
return u
}
// Equal is an identity function since unknown values cannot be modified.
func (u Unknown) Equal(other ref.Val) ref.Val {
return u
}
// Type implements ref.Val.Type.
func (u Unknown) Type() ref.Type {
return UnknownType
}
// Value implements ref.Val.Value.
func (u Unknown) Value() interface{} {
return []int64(u)
}
// IsUnknown returns whether the element ref.Type or ref.Val is equal to the
// UnknownType singleton.
func IsUnknown(val ref.Val) bool {
switch val.(type) {
case Unknown:
return true
default:
return false
}
}

48
vendor/github.com/google/cel-go/common/types/util.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
import (
"github.com/google/cel-go/common/types/ref"
)
// IsUnknownOrError returns whether the input element ref.Val is an ErrType or UnknownType.
func IsUnknownOrError(val ref.Val) bool {
switch val.(type) {
case Unknown, *Err:
return true
}
return false
}
// IsPrimitiveType returns whether the input element ref.Val is a primitive type.
// Note, primitive types do not include well-known types such as Duration and Timestamp.
func IsPrimitiveType(val ref.Val) bool {
switch val.Type() {
case BoolType, BytesType, DoubleType, IntType, StringType, UintType:
return true
}
return false
}
// Equal returns whether the two ref.Value are heterogeneously equivalent.
func Equal(lhs ref.Val, rhs ref.Val) ref.Val {
lNull := lhs == NullValue
rNull := rhs == NullValue
if lNull || rNull {
return Bool(lNull == rNull)
}
return lhs.Equal(rhs)
}