func isSubset(lhs, rhs ref.Val) ref.Val {
	a, ok := lhs.(traits.Lister)
	if !ok {
		return types.ValOrErr(a, "no such overload")
	}
	b, ok := rhs.(traits.Lister)
	if !ok {
		return types.ValOrErr(b, "no such overload")
	}
	m := convertToMap(b)
	for ai := a.Iterator(); ai.HasNext() == types.True; {
		va := ai.Next()
		if m != nil {
			if _, ok := m[va]; !ok {
				return types.False
			}
		} else {
			if !find(b.Iterator(), va) {
				return types.False
			}
		}
	}
	return types.True
}
isSubset returns true value if lhs (list) is a subset of rhs (list).
package conditions
import (
	"fmt"
	"net"
	"time"
	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker/decls"
	"github.com/google/cel-go/common/types"
	"github.com/google/cel-go/common/types/ref"
	"github.com/google/cel-go/common/types/traits"
	"github.com/google/cel-go/interpreter/functions"
	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
	customtypes "github.com/cerbos/cerbos/internal/conditions/types"
)
const (
	exceptFn          = "except"
	hasIntersectionFn = "has_intersection"
	inIPAddrRangeFn   = "inIPAddrRange"
	intersectFn       = "intersect"
	isSubsetFn        = "is_subset"
	timeSinceFn       = "timeSince"
)
func CerbosCELLib() cel.EnvOption {
	return cel.Lib(cerbosLib{})
}
type cerbosLib struct{}
func (clib cerbosLib) CompileOptions() []cel.EnvOption {
	listType := decls.NewListType(decls.NewTypeParamType("A"))
	decls := []*exprpb.Decl{
		decls.NewFunction(inIPAddrRangeFn,
			decls.NewInstanceOverload(
				fmt.Sprintf("%s_string", inIPAddrRangeFn),
				[]*exprpb.Type{decls.String, decls.String},
				decls.Bool,
			),
		),
		decls.NewFunction(timeSinceFn,
			decls.NewInstanceOverload(
				fmt.Sprintf("%s_timestamp", timeSinceFn),
				[]*exprpb.Type{decls.Timestamp},
				decls.Duration,
			),
		),
		decls.NewFunction(exceptFn,
			decls.NewParameterizedInstanceOverload(
				exceptFn,
				[]*exprpb.Type{listType, listType},
				listType,
				[]string{"A"},
			),
		),
		decls.NewFunction(isSubsetFn,
			decls.NewParameterizedInstanceOverload(
				isSubsetFn,
				[]*exprpb.Type{listType, listType},
				decls.Bool,
				[]string{"A"},
			),
		),
		decls.NewFunction(hasIntersectionFn,
			decls.NewParameterizedOverload(
				hasIntersectionFn,
				[]*exprpb.Type{listType, listType},
				decls.Bool,
				[]string{"A"})),
		decls.NewFunction(intersectFn,
			decls.NewParameterizedOverload(
				intersectFn,
				[]*exprpb.Type{listType, listType},
				listType,
				[]string{"A"})),
	}
	decls = append(decls, customtypes.HierarchyDeclrations...)
	return []cel.EnvOption{
		cel.Declarations(decls...),
		cel.Types(customtypes.HierarchyType),
	}
}
func (clib cerbosLib) ProgramOptions() []cel.ProgramOption {
	return []cel.ProgramOption{
		cel.Functions(
			&functions.Overload{
				Operator: inIPAddrRangeFn,
				Binary:   callInStringStringOutBool(clib.inIPAddrRangeFunc),
			},
			&functions.Overload{
				Operator: timeSinceFn,
				Unary:    callInTimestampOutDuration(clib.timeSinceFunc),
			},
			&functions.Overload{
				Operator: fmt.Sprintf("%s_timestamp", timeSinceFn),
				Unary:    callInTimestampOutDuration(clib.timeSinceFunc),
			},
			&functions.Overload{
				Operator: hasIntersectionFn,
				Binary:   hasIntersection,
			},
			&functions.Overload{
				Operator: intersectFn,
				Binary:   intersect,
			},
			&functions.Overload{
				Operator: isSubsetFn,
				Binary:   isSubset,
			},
			&functions.Overload{
				Operator: exceptFn,
				Binary:   exceptList,
			},
			customtypes.HierarchyOverload,
		),
	}
}
func hashable(t ref.Type) bool {
	return t == types.StringType ||
		t == types.IntType ||
		t == types.DoubleType ||
		t == types.DurationType ||
		t == types.TimestampType ||
		t == types.UintType
}
func exceptList(lhs, rhs ref.Val) ref.Val {
	a, ok := lhs.(traits.Lister)
	if !ok {
		return types.ValOrErr(a, "no such overload")
	}
	b, ok := rhs.(traits.Lister)
	if !ok {
		return types.ValOrErr(b, "no such overload")
	}
	m := convertToMap(b)
	var items []ref.Val
	for ai := a.Iterator(); ai.HasNext() == types.True; {
		va := ai.Next()
		var found bool
		if m != nil {
			_, found = m[va]
		} else {
			found = find(b.Iterator(), va)
		}
		if !found {
			items = append(items, va)
		}
	}
	return types.NewRefValList(types.DefaultTypeAdapter, items)
}