lib/globals.go (68 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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 lib import ( "reflect" "time" "github.com/google/cel-go/cel" "github.com/google/cel-go/checker/decls" expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1" ) // Globals returns a cel.EnvOption to configure global variables for the environment. // Each variable will be visible as the key in the vars map. Not all Go variable // types are acceptable to the CEL environment, but Globals will make a best-effort // to map types to their CEL equivalents. This typing is only done for the values // in the map and does not apply recursively if those values are nested. func Globals(vars map[string]interface{}) cel.EnvOption { return cel.Lib(globalsLib(vars)) } type globalsLib map[string]interface{} func (l globalsLib) CompileOptions() []cel.EnvOption { globals := make([]*expr.Decl, 0, len(l)) for name, val := range l { var typ *expr.Type // Do times and []byte first since otherwise duration gets expressed as an // primitive:INT64 and []byte gets expressed as list_type:{elem_type:{dyn:{}}}. switch val.(type) { case time.Duration: typ = decls.Duration case time.Time: typ = decls.Timestamp case []byte: typ = decls.Bytes default: rt := reflect.TypeOf(val) kind := rt.Kind() var ok bool typ, ok = primativeTypeFor(kind) if ok { break } switch kind { case reflect.Slice, reflect.Array: elem, _ := primativeTypeFor(rt.Elem().Kind()) typ = decls.NewListType(elem) case reflect.Map: key, _ := primativeTypeFor(rt.Key().Kind()) elem, _ := primativeTypeFor(rt.Elem().Kind()) typ = decls.NewMapType(key, elem) default: typ = decls.Dyn } } globals = append(globals, decls.NewVar(name, typ)) } return []cel.EnvOption{cel.Declarations(globals...)} } func (l globalsLib) ProgramOptions() []cel.ProgramOption { return []cel.ProgramOption{ cel.Globals(map[string]interface{}(l)), } } func primativeTypeFor(kind reflect.Kind) (typ *expr.Type, definitive bool) { switch kind { case reflect.Bool: return decls.Bool, true case reflect.String: return decls.String, true case reflect.Float32, reflect.Float64: return decls.Double, true case reflect.Int, reflect.Int64: return decls.Int, true case reflect.Uint, reflect.Uint64: return decls.Uint, true default: return decls.Dyn, false } }