1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-25 20:59:28 +01:00

bump to kubernetes v0.32.0-rc.2

Signed-off-by: Amir Alavi <amiralavi7@gmail.com>
This commit is contained in:
Amir Alavi
2024-12-06 10:36:06 -05:00
parent 2c11481856
commit f4c3fdf418
1822 changed files with 68460 additions and 50001 deletions

View File

@@ -33,7 +33,7 @@ descheduler [flags]
--leader-elect Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability.
--leader-elect-lease-duration duration The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled. (default 2m17s)
--leader-elect-renew-deadline duration The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than the lease duration. This is only applicable if leader election is enabled. (default 1m47s)
--leader-elect-resource-lock string The type of resource object that is used for locking during leader election. Supported options are 'leases', 'endpointsleases' and 'configmapsleases'. (default "leases")
--leader-elect-resource-lock string The type of resource object that is used for locking during leader election. Supported options are 'leases'. (default "leases")
--leader-elect-resource-name string The name of resource object that is used for locking during leader election. (default "descheduler")
--leader-elect-resource-namespace string The namespace of resource object that is used for locking during leader election. (default "kube-system")
--leader-elect-retry-period duration The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled. (default 26s)

82
go.mod
View File

@@ -13,16 +13,16 @@ require (
go.opentelemetry.io/otel/sdk v1.28.0
go.opentelemetry.io/otel/trace v1.28.0
google.golang.org/grpc v1.65.0
k8s.io/api v0.31.2
k8s.io/apimachinery v0.31.2
k8s.io/apiserver v0.31.0
k8s.io/client-go v0.31.2
k8s.io/code-generator v0.31.2
k8s.io/component-base v0.31.0
k8s.io/component-helpers v0.31.0
k8s.io/api v0.32.0-rc.2
k8s.io/apimachinery v0.32.0-rc.2
k8s.io/apiserver v0.32.0-rc.2
k8s.io/client-go v0.32.0-rc.2
k8s.io/code-generator v0.32.0-rc.2
k8s.io/component-base v0.32.0-rc.2
k8s.io/component-helpers v0.32.0-rc.2
k8s.io/klog/v2 v2.130.1
k8s.io/metrics v0.31.2
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
k8s.io/metrics v0.32.0-rc.2
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
kubevirt.io/api v1.3.0
kubevirt.io/client-go v1.3.0
kubevirt.io/containerized-data-importer-api v1.60.1 // indirect; drops dependency on o/api
@@ -31,6 +31,7 @@ require (
)
require (
cel.dev/expr v0.18.0 // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
@@ -53,22 +54,21 @@ require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/cel-go v0.22.0 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -84,48 +84,44 @@ require (
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirect
go.etcd.io/etcd/api/v3 v3.5.16 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/protobuf v1.34.2 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.30.0 // indirect
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect
k8s.io/kms v0.31.0 // indirect
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect
k8s.io/kms v0.32.0-rc.2 // indirect
k8s.io/kube-openapi v0.30.0 // indirect
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
)
replace (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f
)
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f

196
go.sum
View File

@@ -1,8 +1,6 @@
cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -34,8 +32,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@@ -58,8 +54,6 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -90,8 +84,8 @@ github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
@@ -101,8 +95,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
@@ -119,8 +113,6 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -140,8 +132,8 @@ github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 h1:oKYOfNR7Hp6
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -159,8 +151,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -179,12 +171,10 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -246,8 +236,8 @@ github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
@@ -268,8 +258,9 @@ github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJK
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4=
github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
@@ -300,8 +291,9 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -319,31 +311,31 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28=
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
go.etcd.io/etcd/client/v2 v2.305.16 h1:kQrn9o5czVNaukf2A2At43cE9ZtWauOtf9vRZuiKXow=
go.etcd.io/etcd/client/v2 v2.305.16/go.mod h1:h9YxWCzcdvZENbfzBTFCnoNumr2ax3F19sKMqHFmXHE=
go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE=
go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50=
go.etcd.io/etcd/pkg/v3 v3.5.16 h1:cnavs5WSPWeK4TYwPYfmcr3Joz9BH+TZ6qoUtz6/+mc=
go.etcd.io/etcd/pkg/v3 v3.5.16/go.mod h1:+lutCZHG5MBBFI/U4eYT5yL7sJfnexsoM20Y0t2uNuY=
go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk=
go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI=
go.etcd.io/etcd/server/v3 v3.5.16 h1:d0/SAdJ3vVsZvF8IFVb1k8zqMZ+heGcNfft71ul9GWE=
go.etcd.io/etcd/server/v3 v3.5.16/go.mod h1:ynhyZZpdDp1Gq49jkUg5mfkDWZwXnn3eIqCqtJnrD/s=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
@@ -364,8 +356,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -381,11 +373,11 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -403,8 +395,9 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -443,11 +436,11 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -460,8 +453,9 @@ golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -505,8 +499,8 @@ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -526,8 +520,8 @@ golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -543,10 +537,10 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -572,8 +566,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -586,10 +580,10 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -609,8 +603,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -639,28 +633,29 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
k8s.io/api v0.32.0-rc.2 h1:mFjTedXmyzuhkl1Fi35t/CY6Dq/VYKCyZoqnxvf6j+g=
k8s.io/api v0.32.0-rc.2/go.mod h1:/O0NxfXqcDG0xKUKKttOnl/DWYJ6K7iqnzVXecg5OKw=
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY=
k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk=
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
k8s.io/apimachinery v0.32.0-rc.2 h1:rsh5rcqBWhYHXuV4GLXyQs26HKnhYq+Plp7iywewHR0=
k8s.io/apimachinery v0.32.0-rc.2/go.mod h1:pfmi1Ug6+bq/azoo9WveGhYBCQ0b+Wm4IgxWGFZ7wRc=
k8s.io/apiserver v0.32.0-rc.2 h1:LH1UDj4RBvzhngtrp/A5Z09dwuJjj1X8spHK8n3GDGs=
k8s.io/apiserver v0.32.0-rc.2/go.mod h1:4MMzPo3GuS5TNvVRMO0jrGZzwBSuUagJgJgNdiCzctY=
k8s.io/client-go v0.32.0-rc.2 h1:x1WFgHIL7hTF+SQw7OvGB/IG7srV74gU+vtcErXI3pk=
k8s.io/client-go v0.32.0-rc.2/go.mod h1:+ePHye0JCEujugXp1oGyBhELUV3w/XcaPdkieeKJ40k=
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
k8s.io/code-generator v0.31.2 h1:xLWxG0HEpMSHfcM//3u3Ro2Hmc6AyyLINQS//Z2GEOI=
k8s.io/code-generator v0.31.2/go.mod h1:eEQHXgBU/m7LDaToDoiz3t97dUUVyOblQdwOr8rivqc=
k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/component-helpers v0.31.0 h1:jyRUKA+GX+q19o81k4x94imjNICn+e6Gzi6T89va1/A=
k8s.io/component-helpers v0.31.0/go.mod h1:MrNIvT4iB7wXIseYSWfHUJB/aNUiFvbilp4qDfBQi6s=
k8s.io/code-generator v0.32.0-rc.2 h1:4V6QHSXLEuTBDu3wZiWAvTIrnimtMWd7geckiPPgh9k=
k8s.io/code-generator v0.32.0-rc.2/go.mod h1:yKxXwnnUnzaPvchydKrWShfwAH8l5O25KdhV1yaz0SA=
k8s.io/component-base v0.32.0-rc.2 h1:Cgf4rBPacMEUYJnFJuV25KFE1NSr5FYu/Beu8oh/0pA=
k8s.io/component-base v0.32.0-rc.2/go.mod h1:sWSaFBT1kESrSbmQHYDLQwBY/25IokFSOsog/62fuaA=
k8s.io/component-helpers v0.32.0-rc.2 h1:WT9Lxj77QfV9YTyNC8/txoscUgZBLJ4aiVfNQ7skIzM=
k8s.io/component-helpers v0.32.0-rc.2/go.mod h1:eV1XPAeKDtiRjK1Pj+dJC4H1C9EVl1lsXEmIR7l2OIE=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo=
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4=
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
@@ -669,16 +664,16 @@ k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kms v0.31.0 h1:KchILPfB1ZE+ka7223mpU5zeFNkmb45jl7RHnlImUaI=
k8s.io/kms v0.31.0/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94=
k8s.io/kms v0.32.0-rc.2 h1:hSZKeB8UbkRDOrJHLKisudPkZ2OmcjJoM2gfdZer87U=
k8s.io/kms v0.32.0-rc.2/go.mod h1:z4El8qehoMz8dCoVw4h0uCMqS8WU2v4J1/3u1RUwHK0=
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM=
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro=
k8s.io/metrics v0.31.2 h1:sQhujR9m3HN/Nu/0fTfTscjnswQl0qkQAodEdGBS0N4=
k8s.io/metrics v0.31.2/go.mod h1:QqqyReApEWO1UEgXOSXiHCQod6yTxYctbAAQBWZkboU=
k8s.io/metrics v0.32.0-rc.2 h1:d+1eMfth1OCiLtJgLLH852o5MMesCj/EgQoe+FPCa94=
k8s.io/metrics v0.32.0-rc.2/go.mod h1:I/20nt0+sjOCTvPs3lqsm6P3l85+dK4nVKoaDKEJOUQ=
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
kubevirt.io/api v1.3.0 h1:9sGElMmnRU50pGED+MPPD2OwQl4S5lvjCUjm+t0mI90=
kubevirt.io/api v1.3.0/go.mod h1:e6LkElYZZm8NcP2gKlFVHZS9pgNhIARHIjSBSfeiP1s=
kubevirt.io/client-go v1.3.0 h1:/HKn4exzwsctEVTwVtEFaeT9D2v4TgWr2SmxITVEZ/4=
@@ -687,17 +682,18 @@ kubevirt.io/containerized-data-importer-api v1.60.1 h1:chmxuINvA7TPmIe8LpShCoKPx
kubevirt.io/containerized-data-importer-api v1.60.1/go.mod h1:8mwrkZIdy8j/LmCyKt2wFXbiMavLUIqDaegaIF67CZs=
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc=
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/mdtoc v1.1.0 h1:q3YtqYzmC2e0hgLXRIOm7/QLuPux1CX3ZHCwlbABxZo=
sigs.k8s.io/mdtoc v1.1.0/go.mod h1:QZLVEdHH2iNIR4uHAZyvFRtjloHgVItk8lo/mzCtq3w=
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=

2
vendor/cel.dev/expr/.bazelversion vendored Normal file
View File

@@ -0,0 +1,2 @@
7.0.1
# Keep this pinned version in parity with cel-go

2
vendor/cel.dev/expr/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
*.pb.go linguist-generated=true
*.pb.go -diff -merge

2
vendor/cel.dev/expr/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bazel-*
MODULE.bazel.lock

34
vendor/cel.dev/expr/BUILD.bazel vendored Normal file
View File

@@ -0,0 +1,34 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
go_library(
name = "expr",
srcs = [
"checked.pb.go",
"eval.pb.go",
"explain.pb.go",
"syntax.pb.go",
"value.pb.go",
],
importpath = "cel.dev/expr",
visibility = ["//visibility:public"],
deps = [
"@org_golang_google_genproto_googleapis_rpc//status:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect",
"@org_golang_google_protobuf//runtime/protoimpl",
"@org_golang_google_protobuf//types/known/anypb",
"@org_golang_google_protobuf//types/known/durationpb",
"@org_golang_google_protobuf//types/known/emptypb",
"@org_golang_google_protobuf//types/known/structpb",
"@org_golang_google_protobuf//types/known/timestamppb",
],
)
alias(
name = "go_default_library",
actual = ":expr",
visibility = ["//visibility:public"],
)

25
vendor/cel.dev/expr/CODE_OF_CONDUCT.md vendored Normal file
View File

@@ -0,0 +1,25 @@
# Contributor Code of Conduct
## Version 0.1.1 (adapted from 0.3b-angular)
As contributors and maintainers of the Common Expression Language
(CEL) project, we pledge to respect everyone who contributes by
posting issues, updating documentation, submitting pull requests,
providing feedback in comments, and any other activities.
Communication through any of CEL's channels (GitHub, Gitter, IRC,
mailing lists, Google+, Twitter, etc.) must be constructive and never
resort to personal attacks, trolling, public or private harassment,
insults, or other unprofessional conduct.
We promise to extend courtesy and respect to everyone involved in this
project regardless of gender, gender identity, sexual orientation,
disability, age, race, ethnicity, religion, or level of experience. We
expect anyone contributing to the project to do the same.
If any member of the community violates this code of conduct, the
maintainers of the CEL project may take action, removing issues,
comments, and PRs or blocking accounts as deemed appropriate.
If you are subject to or witness unacceptable behavior, or have any
other concerns, please email us at
[cel-conduct@google.com](mailto:cel-conduct@google.com).

32
vendor/cel.dev/expr/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,32 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are a
few guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
## What to expect from maintainers
Expect maintainers to respond to new issues or pull requests within a week.
For outstanding and ongoing issues and particularly for long-running
pull requests, expect the maintainers to review within a week of a
contributor asking for a new review. There is no commitment to resolution --
merging or closing a pull request, or fixing or closing an issue -- because some
issues will require more discussion than others.

43
vendor/cel.dev/expr/GOVERNANCE.md vendored Normal file
View File

@@ -0,0 +1,43 @@
# Project Governance
This document defines the governance process for the CEL language. CEL is
Google-developed, but openly governed. Major contributors to the CEL
specification and its corresponding implementations constitute the CEL
Language Council. New members may be added by a unanimous vote of the
Council.
The MAINTAINERS.md file lists the members of the CEL Language Council, and
unofficially indicates the "areas of expertise" of each member with respect
to the publicly available CEL repos.
## Code Changes
Code changes must follow the standard pull request (PR) model documented in the
CONTRIBUTING.md for each CEL repo. All fixes and features must be reviewed by a
maintainer. The maintainer reserves the right to request that any feature
request (FR) or PR be reviewed by the language council.
## Syntax and Semantic Changes
Syntactic and semantic changes must be reviewed by the CEL Language Council.
Maintainers may also request language council review at their discretion.
The review process is as follows:
- Create a Feature Request in the CEL-Spec repo. The feature description will
serve as an abstract for the detailed design document.
- Co-develop a design document with the Language Council.
- Once the proposer gives the design document approval, the document will be
linked to the FR in the CEL-Spec repo and opened for comments to members of
the cel-lang-discuss@googlegroups.com.
- The Language Council will review the design doc at the next council meeting
(once every three weeks) and the council decision included in the document.
If the proposal is approved, the spec will be updated by a maintainer (if
applicable) and a rationale will be included in the CEL-Spec wiki to ensure
future developers may follow CEL's growth and direction over time.
Approved proposals may be implemented by the proposer or by the maintainers as
the parties see fit. At the discretion of the maintainer, changes from the
approved design are permitted during implementation if they improve the user
experience and clarity of the feature.

202
vendor/cel.dev/expr/LICENSE vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

13
vendor/cel.dev/expr/MAINTAINERS.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# CEL Language Council
| Name | Company | Area of Expertise |
|-----------------|--------------|-------------------|
| Alfred Fuller | Facebook | cel-cpp, cel-spec |
| Jim Larson | Google | cel-go, cel-spec |
| Matthais Blume | Google | cel-spec |
| Tristan Swadell | Google | cel-go, cel-spec |
## Emeritus
* Sanjay Ghemawat (Google)
* Wolfgang Grieskamp (Facebook)

70
vendor/cel.dev/expr/MODULE.bazel vendored Normal file
View File

@@ -0,0 +1,70 @@
module(
name = "cel-spec",
)
bazel_dep(
name = "bazel_skylib",
version = "1.7.1",
)
bazel_dep(
name = "gazelle",
version = "0.36.0",
repo_name = "bazel_gazelle",
)
bazel_dep(
name = "googleapis",
version = "0.0.0-20240819-fe8ba054a",
repo_name = "com_google_googleapis",
)
bazel_dep(
name = "protobuf",
version = "26.0",
repo_name = "com_google_protobuf",
)
bazel_dep(
name = "rules_cc",
version = "0.0.9",
)
bazel_dep(
name = "rules_go",
version = "0.49.0",
repo_name = "io_bazel_rules_go",
)
bazel_dep(
name = "rules_java",
version = "7.6.5",
)
bazel_dep(
name = "rules_proto",
version = "6.0.0",
)
bazel_dep(
name = "rules_python",
version = "0.35.0",
)
### PYTHON ###
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
ignore_root_user_error = True,
python_version = "3.11",
)
switched_rules = use_extension("@com_google_googleapis//:extensions.bzl", "switched_rules")
switched_rules.use_languages(
cc = True,
go = True,
java = True,
)
use_repo(switched_rules, "com_google_googleapis_imports")
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.21.1")
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(
go_deps,
"org_golang_google_genproto_googleapis_rpc",
"org_golang_google_protobuf",
)

73
vendor/cel.dev/expr/README.md vendored Normal file
View File

@@ -0,0 +1,73 @@
# Common Expression Language
The Common Expression Language (CEL) implements common semantics for expression
evaluation, enabling different applications to more easily interoperate.
Key Applications
* Security policy: organizations have complex infrastructure and need common
tooling to reason about the system as a whole
* Protocols: expressions are a useful data type and require interoperability
across programming languages and platforms.
Guiding philosophy:
1. Keep it small & fast.
* CEL evaluates in linear time, is mutation free, and not Turing-complete.
This limitation is a feature of the language design, which allows the
implementation to evaluate orders of magnitude faster than equivalently
sandboxed JavaScript.
2. Make it extensible.
* CEL is designed to be embedded in applications, and allows for
extensibility via its context which allows for functions and data to be
provided by the software that embeds it.
3. Developer-friendly.
* The language is approachable to developers. The initial spec was based
on the experience of developing Firebase Rules and usability testing
many prior iterations.
* The library itself and accompanying toolings should be easy to adopt by
teams that seek to integrate CEL into their platforms.
The required components of a system that supports CEL are:
* The textual representation of an expression as written by a developer. It is
of similar syntax to expressions in C/C++/Java/JavaScript
* A representation of the program's abstract syntax tree (AST).
* A compiler library that converts the textual representation to the binary
representation. This can be done ahead of time (in the control plane) or
just before evaluation (in the data plane).
* A context containing one or more typed variables, often protobuf messages.
Most use-cases will use `attribute_context.proto`
* An evaluator library that takes the binary format in the context and
produces a result, usually a Boolean.
For use cases which require persistence or cross-process communcation, it is
highly recommended to serialize the type-checked expression as a protocol
buffer. The CEL team will maintains canonical protocol buffers for ASTs and
will keep these versions identical and wire-compatible in perpetuity:
* [CEL canonical](https://github.com/google/cel-spec/tree/master/proto/cel/expr)
* [CEL v1alpha1](https://github.com/googleapis/googleapis/tree/master/google/api/expr/v1alpha1)
Example of boolean conditions and object construction:
``` c
// Condition
account.balance >= transaction.withdrawal
|| (account.overdraftProtection
&& account.overdraftLimit >= transaction.withdrawal - account.balance)
// Object construction
common.GeoPoint{ latitude: 10.0, longitude: -5.5 }
```
For more detail, see:
* [Introduction](doc/intro.md)
* [Language Definition](doc/langdef.md)
Released under the [Apache License](LICENSE).
Disclaimer: This is not an official Google product.

145
vendor/cel.dev/expr/WORKSPACE vendored Normal file
View File

@@ -0,0 +1,145 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
sha256 = "099a9fb96a376ccbbb7d291ed4ecbdfd42f6bc822ab77ae6f1b5cb9e914e94fa",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
sha256 = "ecba0f04f96b4960a5b250c8e8eeec42281035970aa8852dda73098274d14a1d",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
],
)
http_archive(
name = "rules_proto",
sha256 = "e017528fd1c91c5a33f15493e3a398181a9e821a804eb7ff5acdd1d2d6c2b18d",
strip_prefix = "rules_proto-4.0.0-3.20.0",
urls = [
"https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0-3.20.0.tar.gz",
],
)
# googleapis as of 09/16/2024
http_archive(
name = "com_google_googleapis",
strip_prefix = "googleapis-4082d5e51e8481f6ccc384cacd896f4e78f19dee",
sha256 = "57319889d47578b3c89bf1b3f34888d796a8913d63b32d750a4cd12ed303c4e8",
urls = [
"https://github.com/googleapis/googleapis/archive/4082d5e51e8481f6ccc384cacd896f4e78f19dee.tar.gz",
],
)
# protobuf
http_archive(
name = "com_google_protobuf",
sha256 = "8242327e5df8c80ba49e4165250b8f79a76bd11765facefaaecfca7747dc8da2",
strip_prefix = "protobuf-3.21.5",
urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.21.5.zip"],
)
# googletest
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/master.zip"],
strip_prefix = "googletest-master",
)
# gflags
http_archive(
name = "com_github_gflags_gflags",
sha256 = "6e16c8bc91b1310a44f3965e616383dbda48f83e8c1eaa2370a215057b00cabe",
strip_prefix = "gflags-77592648e3f3be87d6c7123eb81cbad75f9aef5a",
urls = [
"https://mirror.bazel.build/github.com/gflags/gflags/archive/77592648e3f3be87d6c7123eb81cbad75f9aef5a.tar.gz",
"https://github.com/gflags/gflags/archive/77592648e3f3be87d6c7123eb81cbad75f9aef5a.tar.gz",
],
)
# glog
http_archive(
name = "com_google_glog",
sha256 = "1ee310e5d0a19b9d584a855000434bb724aa744745d5b8ab1855c85bff8a8e21",
strip_prefix = "glog-028d37889a1e80e8a07da1b8945ac706259e5fd8",
urls = [
"https://mirror.bazel.build/github.com/google/glog/archive/028d37889a1e80e8a07da1b8945ac706259e5fd8.tar.gz",
"https://github.com/google/glog/archive/028d37889a1e80e8a07da1b8945ac706259e5fd8.tar.gz",
],
)
# absl
http_archive(
name = "com_google_absl",
strip_prefix = "abseil-cpp-master",
urls = ["https://github.com/abseil/abseil-cpp/archive/master.zip"],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
load("@com_google_googleapis//:repository_rules.bzl", "switched_rules_by_language")
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
switched_rules_by_language(
name = "com_google_googleapis_imports",
cc = True,
)
# Do *not* call *_dependencies(), etc, yet. See comment at the end.
# Generated Google APIs protos for Golang
# Generated Google APIs protos for Golang 08/26/2024
go_repository(
name = "org_golang_google_genproto_googleapis_api",
build_file_proto_mode = "disable_global",
importpath = "google.golang.org/genproto/googleapis/api",
sum = "h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=",
version = "v0.0.0-20240826202546-f6391c0de4c7",
)
# Generated Google APIs protos for Golang 08/26/2024
go_repository(
name = "org_golang_google_genproto_googleapis_rpc",
build_file_proto_mode = "disable_global",
importpath = "google.golang.org/genproto/googleapis/rpc",
sum = "h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=",
version = "v0.0.0-20240826202546-f6391c0de4c7",
)
# gRPC deps
go_repository(
name = "org_golang_google_grpc",
build_file_proto_mode = "disable_global",
importpath = "google.golang.org/grpc",
tag = "v1.49.0",
)
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
version = "v0.0.0-20190311183353-d8887717615a",
)
go_repository(
name = "org_golang_x_text",
importpath = "golang.org/x/text",
sum = "h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=",
version = "v0.3.2",
)
# Run the dependencies at the end. These will silently try to import some
# of the above repositories but at different versions, so ours must come first.
go_rules_dependencies()
go_register_toolchains(version = "1.19.1")
gazelle_dependencies()
rules_proto_dependencies()
rules_proto_toolchains()
protobuf_deps()

0
vendor/cel.dev/expr/WORKSPACE.bzlmod vendored Normal file
View File

1432
vendor/cel.dev/expr/checked.pb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

9
vendor/cel.dev/expr/cloudbuild.yaml vendored Normal file
View File

@@ -0,0 +1,9 @@
steps:
- name: 'gcr.io/cloud-builders/bazel:7.0.1'
entrypoint: bazel
args: ['build', '...']
id: bazel-build
waitFor: ['-']
timeout: 15m
options:
machineType: 'N1_HIGHCPU_32'

490
vendor/cel.dev/expr/eval.pb.go generated vendored Normal file
View File

@@ -0,0 +1,490 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.5
// source: cel/expr/eval.proto
package expr
import (
status "google.golang.org/genproto/googleapis/rpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EvalState struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*ExprValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
Results []*EvalState_Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
}
func (x *EvalState) Reset() {
*x = EvalState{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_eval_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EvalState) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EvalState) ProtoMessage() {}
func (x *EvalState) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_eval_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EvalState.ProtoReflect.Descriptor instead.
func (*EvalState) Descriptor() ([]byte, []int) {
return file_cel_expr_eval_proto_rawDescGZIP(), []int{0}
}
func (x *EvalState) GetValues() []*ExprValue {
if x != nil {
return x.Values
}
return nil
}
func (x *EvalState) GetResults() []*EvalState_Result {
if x != nil {
return x.Results
}
return nil
}
type ExprValue struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Kind:
//
// *ExprValue_Value
// *ExprValue_Error
// *ExprValue_Unknown
Kind isExprValue_Kind `protobuf_oneof:"kind"`
}
func (x *ExprValue) Reset() {
*x = ExprValue{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_eval_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ExprValue) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ExprValue) ProtoMessage() {}
func (x *ExprValue) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_eval_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ExprValue.ProtoReflect.Descriptor instead.
func (*ExprValue) Descriptor() ([]byte, []int) {
return file_cel_expr_eval_proto_rawDescGZIP(), []int{1}
}
func (m *ExprValue) GetKind() isExprValue_Kind {
if m != nil {
return m.Kind
}
return nil
}
func (x *ExprValue) GetValue() *Value {
if x, ok := x.GetKind().(*ExprValue_Value); ok {
return x.Value
}
return nil
}
func (x *ExprValue) GetError() *ErrorSet {
if x, ok := x.GetKind().(*ExprValue_Error); ok {
return x.Error
}
return nil
}
func (x *ExprValue) GetUnknown() *UnknownSet {
if x, ok := x.GetKind().(*ExprValue_Unknown); ok {
return x.Unknown
}
return nil
}
type isExprValue_Kind interface {
isExprValue_Kind()
}
type ExprValue_Value struct {
Value *Value `protobuf:"bytes,1,opt,name=value,proto3,oneof"`
}
type ExprValue_Error struct {
Error *ErrorSet `protobuf:"bytes,2,opt,name=error,proto3,oneof"`
}
type ExprValue_Unknown struct {
Unknown *UnknownSet `protobuf:"bytes,3,opt,name=unknown,proto3,oneof"`
}
func (*ExprValue_Value) isExprValue_Kind() {}
func (*ExprValue_Error) isExprValue_Kind() {}
func (*ExprValue_Unknown) isExprValue_Kind() {}
type ErrorSet struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Errors []*status.Status `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
}
func (x *ErrorSet) Reset() {
*x = ErrorSet{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_eval_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrorSet) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorSet) ProtoMessage() {}
func (x *ErrorSet) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_eval_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorSet.ProtoReflect.Descriptor instead.
func (*ErrorSet) Descriptor() ([]byte, []int) {
return file_cel_expr_eval_proto_rawDescGZIP(), []int{2}
}
func (x *ErrorSet) GetErrors() []*status.Status {
if x != nil {
return x.Errors
}
return nil
}
type UnknownSet struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Exprs []int64 `protobuf:"varint,1,rep,packed,name=exprs,proto3" json:"exprs,omitempty"`
}
func (x *UnknownSet) Reset() {
*x = UnknownSet{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_eval_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UnknownSet) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UnknownSet) ProtoMessage() {}
func (x *UnknownSet) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_eval_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UnknownSet.ProtoReflect.Descriptor instead.
func (*UnknownSet) Descriptor() ([]byte, []int) {
return file_cel_expr_eval_proto_rawDescGZIP(), []int{3}
}
func (x *UnknownSet) GetExprs() []int64 {
if x != nil {
return x.Exprs
}
return nil
}
type EvalState_Result struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Expr int64 `protobuf:"varint,1,opt,name=expr,proto3" json:"expr,omitempty"`
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *EvalState_Result) Reset() {
*x = EvalState_Result{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_eval_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EvalState_Result) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EvalState_Result) ProtoMessage() {}
func (x *EvalState_Result) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_eval_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EvalState_Result.ProtoReflect.Descriptor instead.
func (*EvalState_Result) Descriptor() ([]byte, []int) {
return file_cel_expr_eval_proto_rawDescGZIP(), []int{0, 0}
}
func (x *EvalState_Result) GetExpr() int64 {
if x != nil {
return x.Expr
}
return 0
}
func (x *EvalState_Result) GetValue() int64 {
if x != nil {
return x.Value
}
return 0
}
var File_cel_expr_eval_proto protoreflect.FileDescriptor
var file_cel_expr_eval_proto_rawDesc = []byte{
0x0a, 0x13, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x76, 0x61, 0x6c, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x1a,
0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70,
0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa2,
0x01, 0x0a, 0x09, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x06,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63,
0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x65, 0x6c,
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a,
0x32, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70,
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x09, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65, 0x6c, 0x2e,
0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77,
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78,
0x70, 0x72, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64,
0x22, 0x36, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x06,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x0a, 0x55, 0x6e, 0x6b, 0x6e,
0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x42, 0x2c, 0x0a, 0x0c,
0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x09, 0x45, 0x76,
0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64,
0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_cel_expr_eval_proto_rawDescOnce sync.Once
file_cel_expr_eval_proto_rawDescData = file_cel_expr_eval_proto_rawDesc
)
func file_cel_expr_eval_proto_rawDescGZIP() []byte {
file_cel_expr_eval_proto_rawDescOnce.Do(func() {
file_cel_expr_eval_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_eval_proto_rawDescData)
})
return file_cel_expr_eval_proto_rawDescData
}
var file_cel_expr_eval_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_cel_expr_eval_proto_goTypes = []interface{}{
(*EvalState)(nil), // 0: cel.expr.EvalState
(*ExprValue)(nil), // 1: cel.expr.ExprValue
(*ErrorSet)(nil), // 2: cel.expr.ErrorSet
(*UnknownSet)(nil), // 3: cel.expr.UnknownSet
(*EvalState_Result)(nil), // 4: cel.expr.EvalState.Result
(*Value)(nil), // 5: cel.expr.Value
(*status.Status)(nil), // 6: google.rpc.Status
}
var file_cel_expr_eval_proto_depIdxs = []int32{
1, // 0: cel.expr.EvalState.values:type_name -> cel.expr.ExprValue
4, // 1: cel.expr.EvalState.results:type_name -> cel.expr.EvalState.Result
5, // 2: cel.expr.ExprValue.value:type_name -> cel.expr.Value
2, // 3: cel.expr.ExprValue.error:type_name -> cel.expr.ErrorSet
3, // 4: cel.expr.ExprValue.unknown:type_name -> cel.expr.UnknownSet
6, // 5: cel.expr.ErrorSet.errors:type_name -> google.rpc.Status
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_cel_expr_eval_proto_init() }
func file_cel_expr_eval_proto_init() {
if File_cel_expr_eval_proto != nil {
return
}
file_cel_expr_value_proto_init()
if !protoimpl.UnsafeEnabled {
file_cel_expr_eval_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EvalState); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_eval_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ExprValue); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_eval_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ErrorSet); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_eval_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UnknownSet); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_eval_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EvalState_Result); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_cel_expr_eval_proto_msgTypes[1].OneofWrappers = []interface{}{
(*ExprValue_Value)(nil),
(*ExprValue_Error)(nil),
(*ExprValue_Unknown)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cel_expr_eval_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cel_expr_eval_proto_goTypes,
DependencyIndexes: file_cel_expr_eval_proto_depIdxs,
MessageInfos: file_cel_expr_eval_proto_msgTypes,
}.Build()
File_cel_expr_eval_proto = out.File
file_cel_expr_eval_proto_rawDesc = nil
file_cel_expr_eval_proto_goTypes = nil
file_cel_expr_eval_proto_depIdxs = nil
}

236
vendor/cel.dev/expr/explain.pb.go generated vendored Normal file
View File

@@ -0,0 +1,236 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.5
// source: cel/expr/explain.proto
package expr
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Deprecated: Do not use.
type Explain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
ExprSteps []*Explain_ExprStep `protobuf:"bytes,2,rep,name=expr_steps,json=exprSteps,proto3" json:"expr_steps,omitempty"`
}
func (x *Explain) Reset() {
*x = Explain{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_explain_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Explain) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Explain) ProtoMessage() {}
func (x *Explain) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_explain_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Explain.ProtoReflect.Descriptor instead.
func (*Explain) Descriptor() ([]byte, []int) {
return file_cel_expr_explain_proto_rawDescGZIP(), []int{0}
}
func (x *Explain) GetValues() []*Value {
if x != nil {
return x.Values
}
return nil
}
func (x *Explain) GetExprSteps() []*Explain_ExprStep {
if x != nil {
return x.ExprSteps
}
return nil
}
type Explain_ExprStep struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
ValueIndex int32 `protobuf:"varint,2,opt,name=value_index,json=valueIndex,proto3" json:"value_index,omitempty"`
}
func (x *Explain_ExprStep) Reset() {
*x = Explain_ExprStep{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_explain_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Explain_ExprStep) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Explain_ExprStep) ProtoMessage() {}
func (x *Explain_ExprStep) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_explain_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Explain_ExprStep.ProtoReflect.Descriptor instead.
func (*Explain_ExprStep) Descriptor() ([]byte, []int) {
return file_cel_expr_explain_proto_rawDescGZIP(), []int{0, 0}
}
func (x *Explain_ExprStep) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *Explain_ExprStep) GetValueIndex() int32 {
if x != nil {
return x.ValueIndex
}
return 0
}
var File_cel_expr_explain_proto protoreflect.FileDescriptor
var file_cel_expr_explain_proto_rawDesc = []byte{
0x0a, 0x16, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x6c, 0x61,
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78,
0x70, 0x72, 0x1a, 0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x07, 0x45, 0x78, 0x70,
0x6c, 0x61, 0x69, 0x6e, 0x12, 0x27, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e,
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a,
0x0a, 0x65, 0x78, 0x70, 0x72, 0x5f, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70,
0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x53, 0x74, 0x65, 0x70, 0x52, 0x09, 0x65,
0x78, 0x70, 0x72, 0x53, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x3b, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x72,
0x53, 0x74, 0x65, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x02, 0x18, 0x01, 0x42, 0x2f, 0x0a, 0x0c, 0x64, 0x65, 0x76,
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0c, 0x45, 0x78, 0x70, 0x6c, 0x61,
0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64,
0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_cel_expr_explain_proto_rawDescOnce sync.Once
file_cel_expr_explain_proto_rawDescData = file_cel_expr_explain_proto_rawDesc
)
func file_cel_expr_explain_proto_rawDescGZIP() []byte {
file_cel_expr_explain_proto_rawDescOnce.Do(func() {
file_cel_expr_explain_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_explain_proto_rawDescData)
})
return file_cel_expr_explain_proto_rawDescData
}
var file_cel_expr_explain_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_cel_expr_explain_proto_goTypes = []interface{}{
(*Explain)(nil), // 0: cel.expr.Explain
(*Explain_ExprStep)(nil), // 1: cel.expr.Explain.ExprStep
(*Value)(nil), // 2: cel.expr.Value
}
var file_cel_expr_explain_proto_depIdxs = []int32{
2, // 0: cel.expr.Explain.values:type_name -> cel.expr.Value
1, // 1: cel.expr.Explain.expr_steps:type_name -> cel.expr.Explain.ExprStep
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_cel_expr_explain_proto_init() }
func file_cel_expr_explain_proto_init() {
if File_cel_expr_explain_proto != nil {
return
}
file_cel_expr_value_proto_init()
if !protoimpl.UnsafeEnabled {
file_cel_expr_explain_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Explain); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_explain_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Explain_ExprStep); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cel_expr_explain_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cel_expr_explain_proto_goTypes,
DependencyIndexes: file_cel_expr_explain_proto_depIdxs,
MessageInfos: file_cel_expr_explain_proto_msgTypes,
}.Build()
File_cel_expr_explain_proto = out.File
file_cel_expr_explain_proto_rawDesc = nil
file_cel_expr_explain_proto_goTypes = nil
file_cel_expr_explain_proto_depIdxs = nil
}

9
vendor/cel.dev/expr/regen_go_proto.sh vendored Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
bazel build //proto/cel/expr/conformance/...
files=($(bazel aquery 'kind(proto, //proto/cel/expr/conformance/...)' | grep Outputs | grep "[.]pb[.]go" | sed 's/Outputs: \[//' | sed 's/\]//' | tr "," "\n"))
for src in ${files[@]};
do
dst=$(echo $src | sed 's/\(.*\/cel.dev\/expr\/\(.*\)\)/\2/')
echo "copying $dst"
$(cp $src $dst)
done

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
bazel build //proto/cel/expr:all
rm -vf ./*.pb.go
files=( $(bazel cquery //proto/cel/expr:expr_go_proto --output=starlark --starlark:expr="'\n'.join([f.path for f in target.output_groups.go_generated_srcs.to_list()])") )
for src in "${files[@]}";
do
cp -v "${src}" ./
done

1633
vendor/cel.dev/expr/syntax.pb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

653
vendor/cel.dev/expr/value.pb.go generated vendored Normal file
View File

@@ -0,0 +1,653 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.5
// source: cel/expr/value.proto
package expr
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Value struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Kind:
//
// *Value_NullValue
// *Value_BoolValue
// *Value_Int64Value
// *Value_Uint64Value
// *Value_DoubleValue
// *Value_StringValue
// *Value_BytesValue
// *Value_EnumValue
// *Value_ObjectValue
// *Value_MapValue
// *Value_ListValue
// *Value_TypeValue
Kind isValue_Kind `protobuf_oneof:"kind"`
}
func (x *Value) Reset() {
*x = Value{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_value_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Value) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Value) ProtoMessage() {}
func (x *Value) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_value_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Value.ProtoReflect.Descriptor instead.
func (*Value) Descriptor() ([]byte, []int) {
return file_cel_expr_value_proto_rawDescGZIP(), []int{0}
}
func (m *Value) GetKind() isValue_Kind {
if m != nil {
return m.Kind
}
return nil
}
func (x *Value) GetNullValue() structpb.NullValue {
if x, ok := x.GetKind().(*Value_NullValue); ok {
return x.NullValue
}
return structpb.NullValue(0)
}
func (x *Value) GetBoolValue() bool {
if x, ok := x.GetKind().(*Value_BoolValue); ok {
return x.BoolValue
}
return false
}
func (x *Value) GetInt64Value() int64 {
if x, ok := x.GetKind().(*Value_Int64Value); ok {
return x.Int64Value
}
return 0
}
func (x *Value) GetUint64Value() uint64 {
if x, ok := x.GetKind().(*Value_Uint64Value); ok {
return x.Uint64Value
}
return 0
}
func (x *Value) GetDoubleValue() float64 {
if x, ok := x.GetKind().(*Value_DoubleValue); ok {
return x.DoubleValue
}
return 0
}
func (x *Value) GetStringValue() string {
if x, ok := x.GetKind().(*Value_StringValue); ok {
return x.StringValue
}
return ""
}
func (x *Value) GetBytesValue() []byte {
if x, ok := x.GetKind().(*Value_BytesValue); ok {
return x.BytesValue
}
return nil
}
func (x *Value) GetEnumValue() *EnumValue {
if x, ok := x.GetKind().(*Value_EnumValue); ok {
return x.EnumValue
}
return nil
}
func (x *Value) GetObjectValue() *anypb.Any {
if x, ok := x.GetKind().(*Value_ObjectValue); ok {
return x.ObjectValue
}
return nil
}
func (x *Value) GetMapValue() *MapValue {
if x, ok := x.GetKind().(*Value_MapValue); ok {
return x.MapValue
}
return nil
}
func (x *Value) GetListValue() *ListValue {
if x, ok := x.GetKind().(*Value_ListValue); ok {
return x.ListValue
}
return nil
}
func (x *Value) GetTypeValue() string {
if x, ok := x.GetKind().(*Value_TypeValue); ok {
return x.TypeValue
}
return ""
}
type isValue_Kind interface {
isValue_Kind()
}
type Value_NullValue struct {
NullValue structpb.NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,proto3,enum=google.protobuf.NullValue,oneof"`
}
type Value_BoolValue struct {
BoolValue bool `protobuf:"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof"`
}
type Value_Int64Value struct {
Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3,oneof"`
}
type Value_Uint64Value struct {
Uint64Value uint64 `protobuf:"varint,4,opt,name=uint64_value,json=uint64Value,proto3,oneof"`
}
type Value_DoubleValue struct {
DoubleValue float64 `protobuf:"fixed64,5,opt,name=double_value,json=doubleValue,proto3,oneof"`
}
type Value_StringValue struct {
StringValue string `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"`
}
type Value_BytesValue struct {
BytesValue []byte `protobuf:"bytes,7,opt,name=bytes_value,json=bytesValue,proto3,oneof"`
}
type Value_EnumValue struct {
EnumValue *EnumValue `protobuf:"bytes,9,opt,name=enum_value,json=enumValue,proto3,oneof"`
}
type Value_ObjectValue struct {
ObjectValue *anypb.Any `protobuf:"bytes,10,opt,name=object_value,json=objectValue,proto3,oneof"`
}
type Value_MapValue struct {
MapValue *MapValue `protobuf:"bytes,11,opt,name=map_value,json=mapValue,proto3,oneof"`
}
type Value_ListValue struct {
ListValue *ListValue `protobuf:"bytes,12,opt,name=list_value,json=listValue,proto3,oneof"`
}
type Value_TypeValue struct {
TypeValue string `protobuf:"bytes,15,opt,name=type_value,json=typeValue,proto3,oneof"`
}
func (*Value_NullValue) isValue_Kind() {}
func (*Value_BoolValue) isValue_Kind() {}
func (*Value_Int64Value) isValue_Kind() {}
func (*Value_Uint64Value) isValue_Kind() {}
func (*Value_DoubleValue) isValue_Kind() {}
func (*Value_StringValue) isValue_Kind() {}
func (*Value_BytesValue) isValue_Kind() {}
func (*Value_EnumValue) isValue_Kind() {}
func (*Value_ObjectValue) isValue_Kind() {}
func (*Value_MapValue) isValue_Kind() {}
func (*Value_ListValue) isValue_Kind() {}
func (*Value_TypeValue) isValue_Kind() {}
type EnumValue struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *EnumValue) Reset() {
*x = EnumValue{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_value_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EnumValue) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EnumValue) ProtoMessage() {}
func (x *EnumValue) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_value_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EnumValue.ProtoReflect.Descriptor instead.
func (*EnumValue) Descriptor() ([]byte, []int) {
return file_cel_expr_value_proto_rawDescGZIP(), []int{1}
}
func (x *EnumValue) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *EnumValue) GetValue() int32 {
if x != nil {
return x.Value
}
return 0
}
type ListValue struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
}
func (x *ListValue) Reset() {
*x = ListValue{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_value_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListValue) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListValue) ProtoMessage() {}
func (x *ListValue) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_value_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListValue.ProtoReflect.Descriptor instead.
func (*ListValue) Descriptor() ([]byte, []int) {
return file_cel_expr_value_proto_rawDescGZIP(), []int{2}
}
func (x *ListValue) GetValues() []*Value {
if x != nil {
return x.Values
}
return nil
}
type MapValue struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entries []*MapValue_Entry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"`
}
func (x *MapValue) Reset() {
*x = MapValue{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_value_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MapValue) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MapValue) ProtoMessage() {}
func (x *MapValue) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_value_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MapValue.ProtoReflect.Descriptor instead.
func (*MapValue) Descriptor() ([]byte, []int) {
return file_cel_expr_value_proto_rawDescGZIP(), []int{3}
}
func (x *MapValue) GetEntries() []*MapValue_Entry {
if x != nil {
return x.Entries
}
return nil
}
type MapValue_Entry struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *Value `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *MapValue_Entry) Reset() {
*x = MapValue_Entry{}
if protoimpl.UnsafeEnabled {
mi := &file_cel_expr_value_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MapValue_Entry) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MapValue_Entry) ProtoMessage() {}
func (x *MapValue_Entry) ProtoReflect() protoreflect.Message {
mi := &file_cel_expr_value_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MapValue_Entry.ProtoReflect.Descriptor instead.
func (*MapValue_Entry) Descriptor() ([]byte, []int) {
return file_cel_expr_value_proto_rawDescGZIP(), []int{3, 0}
}
func (x *MapValue_Entry) GetKey() *Value {
if x != nil {
return x.Key
}
return nil
}
func (x *MapValue_Entry) GetValue() *Value {
if x != nil {
return x.Value
}
return nil
}
var File_cel_expr_value_proto protoreflect.FileDescriptor
var file_cel_expr_value_proto_rawDesc = []byte{
0x0a, 0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72,
0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x04, 0x0a, 0x05, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4e, 0x75, 0x6c, 0x6c, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6e, 0x75, 0x6c, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56,
0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x0b, 0x75, 0x69,
0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x64, 0x6f, 0x75,
0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x48,
0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23,
0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65,
0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x65, 0x6c,
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48,
0x00, 0x52, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x39, 0x0a, 0x0c,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65, 0x6c,
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00,
0x52, 0x08, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x6c, 0x69,
0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x12, 0x1f, 0x0a, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0f,
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x79, 0x70, 0x65, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x35, 0x0a, 0x09, 0x45, 0x6e, 0x75,
0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x22, 0x34, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a,
0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x08, 0x4d, 0x61, 0x70, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e,
0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07,
0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x51, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x21, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2d, 0x0a, 0x0c, 0x64, 0x65,
0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0a, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64, 0x65,
0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_cel_expr_value_proto_rawDescOnce sync.Once
file_cel_expr_value_proto_rawDescData = file_cel_expr_value_proto_rawDesc
)
func file_cel_expr_value_proto_rawDescGZIP() []byte {
file_cel_expr_value_proto_rawDescOnce.Do(func() {
file_cel_expr_value_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_value_proto_rawDescData)
})
return file_cel_expr_value_proto_rawDescData
}
var file_cel_expr_value_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_cel_expr_value_proto_goTypes = []interface{}{
(*Value)(nil), // 0: cel.expr.Value
(*EnumValue)(nil), // 1: cel.expr.EnumValue
(*ListValue)(nil), // 2: cel.expr.ListValue
(*MapValue)(nil), // 3: cel.expr.MapValue
(*MapValue_Entry)(nil), // 4: cel.expr.MapValue.Entry
(structpb.NullValue)(0), // 5: google.protobuf.NullValue
(*anypb.Any)(nil), // 6: google.protobuf.Any
}
var file_cel_expr_value_proto_depIdxs = []int32{
5, // 0: cel.expr.Value.null_value:type_name -> google.protobuf.NullValue
1, // 1: cel.expr.Value.enum_value:type_name -> cel.expr.EnumValue
6, // 2: cel.expr.Value.object_value:type_name -> google.protobuf.Any
3, // 3: cel.expr.Value.map_value:type_name -> cel.expr.MapValue
2, // 4: cel.expr.Value.list_value:type_name -> cel.expr.ListValue
0, // 5: cel.expr.ListValue.values:type_name -> cel.expr.Value
4, // 6: cel.expr.MapValue.entries:type_name -> cel.expr.MapValue.Entry
0, // 7: cel.expr.MapValue.Entry.key:type_name -> cel.expr.Value
0, // 8: cel.expr.MapValue.Entry.value:type_name -> cel.expr.Value
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_cel_expr_value_proto_init() }
func file_cel_expr_value_proto_init() {
if File_cel_expr_value_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_cel_expr_value_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Value); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_value_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EnumValue); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_value_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListValue); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_value_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MapValue); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cel_expr_value_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MapValue_Entry); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_cel_expr_value_proto_msgTypes[0].OneofWrappers = []interface{}{
(*Value_NullValue)(nil),
(*Value_BoolValue)(nil),
(*Value_Int64Value)(nil),
(*Value_Uint64Value)(nil),
(*Value_DoubleValue)(nil),
(*Value_StringValue)(nil),
(*Value_BytesValue)(nil),
(*Value_EnumValue)(nil),
(*Value_ObjectValue)(nil),
(*Value_MapValue)(nil),
(*Value_ListValue)(nil),
(*Value_TypeValue)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cel_expr_value_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cel_expr_value_proto_goTypes,
DependencyIndexes: file_cel_expr_value_proto_depIdxs,
MessageInfos: file_cel_expr_value_proto_msgTypes,
}.Build()
File_cel_expr_value_proto = out.File
file_cel_expr_value_proto_rawDesc = nil
file_cel_expr_value_proto_goTypes = nil
file_cel_expr_value_proto_depIdxs = nil
}

61
vendor/github.com/go-openapi/jsonpointer/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,61 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 45
maligned:
suggest-new: true
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
linters:
enable-all: true
disable:
- maligned
- unparam
- lll
- gochecknoinits
- gochecknoglobals
- funlen
- godox
- gocognit
- whitespace
- wsl
- wrapcheck
- testpackage
- nlreturn
- gomnd
- exhaustivestruct
- goerr113
- errorlint
- nestif
- godot
- gofumpt
- paralleltest
- tparallel
- thelper
- ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View File

@@ -1,6 +1,10 @@
# gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# gojsonpointer [![Build Status](https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonpointer/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer.svg)](https://pkg.go.dev/github.com/go-openapi/jsonpointer)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonpointer)](https://goreportcard.com/report/github.com/go-openapi/jsonpointer)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer)
An implementation of JSON Pointer - Go language
## Status

View File

@@ -110,19 +110,39 @@ func SetForToken(document any, decodedToken string, value any) (any, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
}
func isNil(input any) bool {
if input == nil {
return true
}
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
}
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
switch typed := node.(type) {
case JSONPointable:
r, err := typed.JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
return getSingleImpl(*typed, decodedToken, nameProvider)
}
switch kind {
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
@@ -170,7 +190,7 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameP
return node.(JSONSetable).JSONSet(decodedToken, data)
}
switch rValue.Kind() {
switch rValue.Kind() { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
@@ -231,8 +251,7 @@ func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.K
if err != nil {
return nil, knd, err
}
node, kind = r, knd
node = r
}
rValue := reflect.ValueOf(node)
@@ -245,7 +264,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values")
return errors.New("only structs, pointers, maps and slices are supported for setting values")
}
if nameProvider == nil {
@@ -284,7 +303,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
continue
}
switch kind {
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
@@ -405,11 +424,11 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
case json.Delim:
switch tk {
case '{':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return 0, err
}
case '[':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return 0, err
}
}
@@ -435,20 +454,21 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
if err != nil {
return 0, err
}
switch tk := tk.(type) {
case json.Delim:
switch tk {
if delim, isDelim := tk.(json.Delim); isDelim {
switch delim {
case '{':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return 0, err
}
case '[':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return 0, err
}
}
}
}
if !dec.More() {
return 0, fmt.Errorf("token reference %q not found", decodedToken)
}
@@ -456,27 +476,27 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
}
// drainSingle drains a single level of object or array.
// The decoder has to guarantee the begining delim (i.e. '{' or '[') has been consumed.
// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed.
func drainSingle(dec *json.Decoder) error {
for dec.More() {
tk, err := dec.Token()
if err != nil {
return err
}
switch tk := tk.(type) {
case json.Delim:
switch tk {
if delim, isDelim := tk.(json.Delim); isDelim {
switch delim {
case '{':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return err
}
case '[':
if err := drainSingle(dec); err != nil {
if err = drainSingle(dec); err != nil {
return err
}
}
}
}
// Consumes the ending delim
if _, err := dec.Token(); err != nil {
return err
@@ -498,14 +518,14 @@ const (
// Unescape unescapes a json pointer reference token string to the original representation
func Unescape(token string) string {
step1 := strings.Replace(token, encRefTok1, decRefTok1, -1)
step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1)
step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
return step2
}
// Escape escapes a pointer reference token string
func Escape(token string) string {
step1 := strings.Replace(token, decRefTok0, encRefTok0, -1)
step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1)
step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
return step2
}

View File

@@ -2,3 +2,4 @@ secrets.yml
vendor
Godeps
.idea
*.out

View File

@@ -4,14 +4,14 @@ linters-settings:
golint:
min-confidence: 0
gocyclo:
min-complexity: 25
min-complexity: 45
maligned:
suggest-new: true
dupl:
threshold: 100
threshold: 200
goconst:
min-len: 3
min-occurrences: 2
min-occurrences: 3
linters:
enable-all: true
@@ -20,35 +20,41 @@ linters:
- lll
- gochecknoinits
- gochecknoglobals
- nlreturn
- testpackage
- funlen
- godox
- gocognit
- whitespace
- wsl
- wrapcheck
- testpackage
- nlreturn
- gomnd
- exhaustive
- exhaustivestruct
- goerr113
- wsl
- whitespace
- gofumpt
- godot
- errorlint
- nestif
- godox
- funlen
- gci
- gocognit
- godot
- gofumpt
- paralleltest
- tparallel
- thelper
- ifshort
- gomoddirectives
- cyclop
- forcetypeassert
- ireturn
- tagliatelle
- varnamelen
- goimports
- tenv
- golint
- exhaustruct
- nilnil
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

52
vendor/github.com/go-openapi/swag/BENCHMARK.md generated vendored Normal file
View File

@@ -0,0 +1,52 @@
# Benchmarks
## Name mangling utilities
```bash
go test -bench XXX -run XXX -benchtime 30s
```
### Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df
```
goos: linux
goarch: amd64
pkg: github.com/go-openapi/swag
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkToXXXName/ToGoName-4 862623 44101 ns/op 10450 B/op 732 allocs/op
BenchmarkToXXXName/ToVarName-4 853656 40728 ns/op 10468 B/op 734 allocs/op
BenchmarkToXXXName/ToFileName-4 1268312 27813 ns/op 9785 B/op 617 allocs/op
BenchmarkToXXXName/ToCommandName-4 1276322 27903 ns/op 9785 B/op 617 allocs/op
BenchmarkToXXXName/ToHumanNameLower-4 895334 40354 ns/op 10472 B/op 731 allocs/op
BenchmarkToXXXName/ToHumanNameTitle-4 882441 40678 ns/op 10566 B/op 749 allocs/op
```
### Benchmarks after PR #79
~ x10 performance improvement and ~ /100 memory allocations.
```
goos: linux
goarch: amd64
pkg: github.com/go-openapi/swag
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkToXXXName/ToGoName-4 9595830 3991 ns/op 42 B/op 5 allocs/op
BenchmarkToXXXName/ToVarName-4 9194276 3984 ns/op 62 B/op 7 allocs/op
BenchmarkToXXXName/ToFileName-4 17002711 2123 ns/op 147 B/op 7 allocs/op
BenchmarkToXXXName/ToCommandName-4 16772926 2111 ns/op 147 B/op 7 allocs/op
BenchmarkToXXXName/ToHumanNameLower-4 9788331 3749 ns/op 92 B/op 6 allocs/op
BenchmarkToXXXName/ToHumanNameTitle-4 9188260 3941 ns/op 104 B/op 6 allocs/op
```
```
goos: linux
goarch: amd64
pkg: github.com/go-openapi/swag
cpu: AMD Ryzen 7 5800X 8-Core Processor
BenchmarkToXXXName/ToGoName-16 18527378 1972 ns/op 42 B/op 5 allocs/op
BenchmarkToXXXName/ToVarName-16 15552692 2093 ns/op 62 B/op 7 allocs/op
BenchmarkToXXXName/ToFileName-16 32161176 1117 ns/op 147 B/op 7 allocs/op
BenchmarkToXXXName/ToCommandName-16 32256634 1137 ns/op 147 B/op 7 allocs/op
BenchmarkToXXXName/ToHumanNameLower-16 18599661 1946 ns/op 92 B/op 6 allocs/op
BenchmarkToXXXName/ToHumanNameTitle-16 17581353 2054 ns/op 105 B/op 6 allocs/op
```

View File

@@ -1,7 +1,8 @@
# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# Swag [![Build Status](https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/swag.svg)](https://pkg.go.dev/github.com/go-openapi/swag)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag)
Contains a bunch of helper functions for go-openapi and go-swagger projects.
@@ -18,4 +19,5 @@ You may also use it standalone for your projects.
This repo has only few dependencies outside of the standard library:
* YAML utilities depend on gopkg.in/yaml.v2
* YAML utilities depend on `gopkg.in/yaml.v3`
* `github.com/mailru/easyjson v0.7.7`

202
vendor/github.com/go-openapi/swag/initialism_index.go generated vendored Normal file
View File

@@ -0,0 +1,202 @@
// Copyright 2015 go-swagger maintainers
//
// 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 swag
import (
"sort"
"strings"
"sync"
)
var (
// commonInitialisms are common acronyms that are kept as whole uppercased words.
commonInitialisms *indexOfInitialisms
// initialisms is a slice of sorted initialisms
initialisms []string
// a copy of initialisms pre-baked as []rune
initialismsRunes [][]rune
initialismsUpperCased [][]rune
isInitialism func(string) bool
maxAllocMatches int
)
func init() {
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
configuredInitialisms := map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTPS": true,
"HTTP": true,
"ID": true,
"IP": true,
"IPv4": true,
"IPv6": true,
"JSON": true,
"LHS": true,
"OAI": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
}
// a thread-safe index of initialisms
commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
initialisms = commonInitialisms.sorted()
initialismsRunes = asRunes(initialisms)
initialismsUpperCased = asUpperCased(initialisms)
maxAllocMatches = maxAllocHeuristic(initialismsRunes)
// a test function
isInitialism = commonInitialisms.isInitialism
}
func asRunes(in []string) [][]rune {
out := make([][]rune, len(in))
for i, initialism := range in {
out[i] = []rune(initialism)
}
return out
}
func asUpperCased(in []string) [][]rune {
out := make([][]rune, len(in))
for i, initialism := range in {
out[i] = []rune(upper(trim(initialism)))
}
return out
}
func maxAllocHeuristic(in [][]rune) int {
heuristic := make(map[rune]int)
for _, initialism := range in {
heuristic[initialism[0]]++
}
var maxAlloc int
for _, val := range heuristic {
if val > maxAlloc {
maxAlloc = val
}
}
return maxAlloc
}
// AddInitialisms add additional initialisms
func AddInitialisms(words ...string) {
for _, word := range words {
// commonInitialisms[upper(word)] = true
commonInitialisms.add(upper(word))
}
// sort again
initialisms = commonInitialisms.sorted()
initialismsRunes = asRunes(initialisms)
initialismsUpperCased = asUpperCased(initialisms)
}
// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
// Since go1.9, this may be implemented with sync.Map.
type indexOfInitialisms struct {
sortMutex *sync.Mutex
index *sync.Map
}
func newIndexOfInitialisms() *indexOfInitialisms {
return &indexOfInitialisms{
sortMutex: new(sync.Mutex),
index: new(sync.Map),
}
}
func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
for k, v := range initial {
m.index.Store(k, v)
}
return m
}
func (m *indexOfInitialisms) isInitialism(key string) bool {
_, ok := m.index.Load(key)
return ok
}
func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
m.index.Store(key, true)
return m
}
func (m *indexOfInitialisms) sorted() (result []string) {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
m.index.Range(func(key, _ interface{}) bool {
k := key.(string)
result = append(result, k)
return true
})
sort.Sort(sort.Reverse(byInitialism(result)))
return
}
type byInitialism []string
func (s byInitialism) Len() int {
return len(s)
}
func (s byInitialism) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s byInitialism) Less(i, j int) bool {
if len(s[i]) != len(s[j]) {
return len(s[i]) < len(s[j])
}
return strings.Compare(s[i], s[j]) > 0
}

View File

@@ -21,6 +21,7 @@ import (
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"runtime"
"strings"
@@ -40,43 +41,97 @@ var LoadHTTPBasicAuthPassword = ""
var LoadHTTPCustomHeaders = map[string]string{}
// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
func LoadFromFileOrHTTP(path string) ([]byte, error) {
return LoadStrategy(path, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path)
func LoadFromFileOrHTTP(pth string) ([]byte, error) {
return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(pth)
}
// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in
// timeout arg allows for per request overriding of the request timeout
func LoadFromFileOrHTTPWithTimeout(path string, timeout time.Duration) ([]byte, error) {
return LoadStrategy(path, os.ReadFile, loadHTTPBytes(timeout))(path)
func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration) ([]byte, error) {
return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(timeout))(pth)
}
// LoadStrategy returns a loader function for a given path or uri
func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) {
if strings.HasPrefix(path, "http") {
// LoadStrategy returns a loader function for a given path or URI.
//
// The load strategy returns the remote load for any path starting with `http`.
// So this works for any URI with a scheme `http` or `https`.
//
// The fallback strategy is to call the local loader.
//
// The local loader takes a local file system path (absolute or relative) as argument,
// or alternatively a `file://...` URI, **without host** (see also below for windows).
//
// There are a few liberalities, initially intended to be tolerant regarding the URI syntax,
// especially on windows.
//
// Before the local loader is called, the given path is transformed:
// - percent-encoded characters are unescaped
// - simple paths (e.g. `./folder/file`) are passed as-is
// - on windows, occurrences of `/` are replaced by `\`, so providing a relative path such a `folder/file` works too.
//
// For paths provided as URIs with the "file" scheme, please note that:
// - `file://` is simply stripped.
// This means that the host part of the URI is not parsed at all.
// For example, `file:///folder/file" becomes "/folder/file`,
// but `file://localhost/folder/file` becomes `localhost/folder/file` on unix systems.
// Similarly, `file://./folder/file` yields `./folder/file`.
// - on windows, `file://...` can take a host so as to specify an UNC share location.
//
// Reminder about windows-specifics:
// - `file://host/folder/file` becomes an UNC path like `\\host\folder\file` (no port specification is supported)
// - `file:///c:/folder/file` becomes `C:\folder\file`
// - `file://c:/folder/file` is tolerated (without leading `/`) and becomes `c:\folder\file`
func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) {
if strings.HasPrefix(pth, "http") {
return remote
}
return func(pth string) ([]byte, error) {
upth, err := pathUnescape(pth)
return func(p string) ([]byte, error) {
upth, err := url.PathUnescape(p)
if err != nil {
return nil, err
}
if strings.HasPrefix(pth, `file://`) {
if runtime.GOOS == "windows" {
// support for canonical file URIs on windows.
// Zero tolerance here for dodgy URIs.
u, _ := url.Parse(upth)
if u.Host != "" {
// assume UNC name (volume share)
// file://host/share/folder\... ==> \\host\share\path\folder
// NOTE: UNC port not yet supported
upth = strings.Join([]string{`\`, u.Host, u.Path}, `\`)
} else {
// file:///c:/folder/... ==> just remove the leading slash
upth = strings.TrimPrefix(upth, `file:///`)
}
} else {
upth = strings.TrimPrefix(upth, `file://`)
if !strings.HasPrefix(p, `file://`) {
// regular file path provided: just normalize slashes
return local(filepath.FromSlash(upth))
}
if runtime.GOOS != "windows" {
// crude processing: this leaves full URIs with a host with a (mostly) unexpected result
upth = strings.TrimPrefix(upth, `file://`)
return local(filepath.FromSlash(upth))
}
// windows-only pre-processing of file://... URIs
// support for canonical file URIs on windows.
u, err := url.Parse(filepath.ToSlash(upth))
if err != nil {
return nil, err
}
if u.Host != "" {
// assume UNC name (volume share)
// NOTE: UNC port not yet supported
// when the "host" segment is a drive letter:
// file://C:/folder/... => C:\folder
upth = path.Clean(strings.Join([]string{u.Host, u.Path}, `/`))
if !strings.HasSuffix(u.Host, ":") && u.Host[0] != '.' {
// tolerance: if we have a leading dot, this can't be a host
// file://host/share/folder\... ==> \\host\share\path\folder
upth = "//" + upth
}
} else {
// no host, let's figure out if this is a drive letter
upth = strings.TrimPrefix(upth, `file://`)
first, _, _ := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/")
if strings.HasSuffix(first, ":") {
// drive letter in the first segment:
// file:///c:/folder/... ==> strip the leading slash
upth = strings.TrimPrefix(upth, `/`)
}
}

View File

@@ -14,74 +14,80 @@
package swag
import "unicode"
import (
"unicode"
"unicode/utf8"
)
type (
nameLexem interface {
GetUnsafeGoName() string
GetOriginal() string
IsInitialism() bool
}
lexemKind uint8
initialismNameLexem struct {
nameLexem struct {
original string
matchedInitialism string
}
casualNameLexem struct {
original string
kind lexemKind
}
)
func newInitialismNameLexem(original, matchedInitialism string) *initialismNameLexem {
return &initialismNameLexem{
const (
lexemKindCasualName lexemKind = iota
lexemKindInitialismName
)
func newInitialismNameLexem(original, matchedInitialism string) nameLexem {
return nameLexem{
kind: lexemKindInitialismName,
original: original,
matchedInitialism: matchedInitialism,
}
}
func newCasualNameLexem(original string) *casualNameLexem {
return &casualNameLexem{
func newCasualNameLexem(original string) nameLexem {
return nameLexem{
kind: lexemKindCasualName,
original: original,
}
}
func (l *initialismNameLexem) GetUnsafeGoName() string {
return l.matchedInitialism
}
func (l nameLexem) GetUnsafeGoName() string {
if l.kind == lexemKindInitialismName {
return l.matchedInitialism
}
var (
first rune
rest string
)
func (l *casualNameLexem) GetUnsafeGoName() string {
var first rune
var rest string
for i, orig := range l.original {
if i == 0 {
first = orig
continue
}
if i > 0 {
rest = l.original[i:]
break
}
}
if len(l.original) > 1 {
return string(unicode.ToUpper(first)) + lower(rest)
b := poolOfBuffers.BorrowBuffer(utf8.UTFMax + len(rest))
defer func() {
poolOfBuffers.RedeemBuffer(b)
}()
b.WriteRune(unicode.ToUpper(first))
b.WriteString(lower(rest))
return b.String()
}
return l.original
}
func (l *initialismNameLexem) GetOriginal() string {
func (l nameLexem) GetOriginal() string {
return l.original
}
func (l *casualNameLexem) GetOriginal() string {
return l.original
}
func (l *initialismNameLexem) IsInitialism() bool {
return true
}
func (l *casualNameLexem) IsInitialism() bool {
return false
func (l nameLexem) IsInitialism() bool {
return l.kind == lexemKindInitialismName
}

View File

@@ -1,24 +0,0 @@
// Copyright 2015 go-swagger maintainers
//
// 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.
//go:build go1.8
// +build go1.8
package swag
import "net/url"
func pathUnescape(path string) (string, error) {
return url.PathUnescape(path)
}

View File

@@ -1,68 +0,0 @@
// Copyright 2015 go-swagger maintainers
//
// 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.
//go:build go1.9
// +build go1.9
package swag
import (
"sort"
"sync"
)
// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
// Since go1.9, this may be implemented with sync.Map.
type indexOfInitialisms struct {
sortMutex *sync.Mutex
index *sync.Map
}
func newIndexOfInitialisms() *indexOfInitialisms {
return &indexOfInitialisms{
sortMutex: new(sync.Mutex),
index: new(sync.Map),
}
}
func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
for k, v := range initial {
m.index.Store(k, v)
}
return m
}
func (m *indexOfInitialisms) isInitialism(key string) bool {
_, ok := m.index.Load(key)
return ok
}
func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
m.index.Store(key, true)
return m
}
func (m *indexOfInitialisms) sorted() (result []string) {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
m.index.Range(func(key, value interface{}) bool {
k := key.(string)
result = append(result, k)
return true
})
sort.Sort(sort.Reverse(byInitialism(result)))
return
}

View File

@@ -1,24 +0,0 @@
// Copyright 2015 go-swagger maintainers
//
// 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.
//go:build !go1.8
// +build !go1.8
package swag
import "net/url"
func pathUnescape(path string) (string, error) {
return url.QueryUnescape(path)
}

View File

@@ -1,70 +0,0 @@
// Copyright 2015 go-swagger maintainers
//
// 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.
//go:build !go1.9
// +build !go1.9
package swag
import (
"sort"
"sync"
)
// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
// Before go1.9, this may be implemented with a mutex on the map.
type indexOfInitialisms struct {
getMutex *sync.Mutex
index map[string]bool
}
func newIndexOfInitialisms() *indexOfInitialisms {
return &indexOfInitialisms{
getMutex: new(sync.Mutex),
index: make(map[string]bool, 50),
}
}
func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
m.getMutex.Lock()
defer m.getMutex.Unlock()
for k, v := range initial {
m.index[k] = v
}
return m
}
func (m *indexOfInitialisms) isInitialism(key string) bool {
m.getMutex.Lock()
defer m.getMutex.Unlock()
_, ok := m.index[key]
return ok
}
func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
m.getMutex.Lock()
defer m.getMutex.Unlock()
m.index[key] = true
return m
}
func (m *indexOfInitialisms) sorted() (result []string) {
m.getMutex.Lock()
defer m.getMutex.Unlock()
for k := range m.index {
result = append(result, k)
}
sort.Sort(sort.Reverse(byInitialism(result)))
return
}

View File

@@ -15,124 +15,269 @@
package swag
import (
"bytes"
"sync"
"unicode"
"unicode/utf8"
)
var nameReplaceTable = map[rune]string{
'@': "At ",
'&': "And ",
'|': "Pipe ",
'$': "Dollar ",
'!': "Bang ",
'-': "",
'_': "",
}
type (
splitter struct {
postSplitInitialismCheck bool
initialisms []string
initialismsRunes [][]rune
initialismsUpperCased [][]rune // initialisms cached in their trimmed, upper-cased version
postSplitInitialismCheck bool
}
splitterOption func(*splitter) *splitter
splitterOption func(*splitter)
initialismMatch struct {
body []rune
start, end int
complete bool
}
initialismMatches []initialismMatch
)
// split calls the splitter; splitter provides more control and post options
func split(str string) []string {
lexems := newSplitter().split(str)
result := make([]string, 0, len(lexems))
type (
// memory pools of temporary objects.
//
// These are used to recycle temporarily allocated objects
// and relieve the GC from undue pressure.
for _, lexem := range lexems {
matchesPool struct {
*sync.Pool
}
buffersPool struct {
*sync.Pool
}
lexemsPool struct {
*sync.Pool
}
splittersPool struct {
*sync.Pool
}
)
var (
// poolOfMatches holds temporary slices for recycling during the initialism match process
poolOfMatches = matchesPool{
Pool: &sync.Pool{
New: func() any {
s := make(initialismMatches, 0, maxAllocMatches)
return &s
},
},
}
poolOfBuffers = buffersPool{
Pool: &sync.Pool{
New: func() any {
return new(bytes.Buffer)
},
},
}
poolOfLexems = lexemsPool{
Pool: &sync.Pool{
New: func() any {
s := make([]nameLexem, 0, maxAllocMatches)
return &s
},
},
}
poolOfSplitters = splittersPool{
Pool: &sync.Pool{
New: func() any {
s := newSplitter()
return &s
},
},
}
)
// nameReplaceTable finds a word representation for special characters.
func nameReplaceTable(r rune) (string, bool) {
switch r {
case '@':
return "At ", true
case '&':
return "And ", true
case '|':
return "Pipe ", true
case '$':
return "Dollar ", true
case '!':
return "Bang ", true
case '-':
return "", true
case '_':
return "", true
default:
return "", false
}
}
// split calls the splitter.
//
// Use newSplitter for more control and options
func split(str string) []string {
s := poolOfSplitters.BorrowSplitter()
lexems := s.split(str)
result := make([]string, 0, len(*lexems))
for _, lexem := range *lexems {
result = append(result, lexem.GetOriginal())
}
poolOfLexems.RedeemLexems(lexems)
poolOfSplitters.RedeemSplitter(s)
return result
}
func (s *splitter) split(str string) []nameLexem {
return s.toNameLexems(str)
}
func newSplitter(options ...splitterOption) *splitter {
splitter := &splitter{
func newSplitter(options ...splitterOption) splitter {
s := splitter{
postSplitInitialismCheck: false,
initialisms: initialisms,
initialismsRunes: initialismsRunes,
initialismsUpperCased: initialismsUpperCased,
}
for _, option := range options {
splitter = option(splitter)
option(&s)
}
return splitter
}
// withPostSplitInitialismCheck allows to catch initialisms after main split process
func withPostSplitInitialismCheck(s *splitter) *splitter {
s.postSplitInitialismCheck = true
return s
}
type (
initialismMatch struct {
start, end int
body []rune
complete bool
}
initialismMatches []*initialismMatch
)
// withPostSplitInitialismCheck allows to catch initialisms after main split process
func withPostSplitInitialismCheck(s *splitter) {
s.postSplitInitialismCheck = true
}
func (s *splitter) toNameLexems(name string) []nameLexem {
func (p matchesPool) BorrowMatches() *initialismMatches {
s := p.Get().(*initialismMatches)
*s = (*s)[:0] // reset slice, keep allocated capacity
return s
}
func (p buffersPool) BorrowBuffer(size int) *bytes.Buffer {
s := p.Get().(*bytes.Buffer)
s.Reset()
if s.Cap() < size {
s.Grow(size)
}
return s
}
func (p lexemsPool) BorrowLexems() *[]nameLexem {
s := p.Get().(*[]nameLexem)
*s = (*s)[:0] // reset slice, keep allocated capacity
return s
}
func (p splittersPool) BorrowSplitter(options ...splitterOption) *splitter {
s := p.Get().(*splitter)
s.postSplitInitialismCheck = false // reset options
for _, apply := range options {
apply(s)
}
return s
}
func (p matchesPool) RedeemMatches(s *initialismMatches) {
p.Put(s)
}
func (p buffersPool) RedeemBuffer(s *bytes.Buffer) {
p.Put(s)
}
func (p lexemsPool) RedeemLexems(s *[]nameLexem) {
p.Put(s)
}
func (p splittersPool) RedeemSplitter(s *splitter) {
p.Put(s)
}
func (m initialismMatch) isZero() bool {
return m.start == 0 && m.end == 0
}
func (s splitter) split(name string) *[]nameLexem {
nameRunes := []rune(name)
matches := s.gatherInitialismMatches(nameRunes)
if matches == nil {
return poolOfLexems.BorrowLexems()
}
return s.mapMatchesToNameLexems(nameRunes, matches)
}
func (s *splitter) gatherInitialismMatches(nameRunes []rune) initialismMatches {
matches := make(initialismMatches, 0)
func (s splitter) gatherInitialismMatches(nameRunes []rune) *initialismMatches {
var matches *initialismMatches
for currentRunePosition, currentRune := range nameRunes {
newMatches := make(initialismMatches, 0, len(matches))
// recycle these allocations as we loop over runes
// with such recycling, only 2 slices should be allocated per call
// instead of o(n).
newMatches := poolOfMatches.BorrowMatches()
// check current initialism matches
for _, match := range matches {
if keepCompleteMatch := match.complete; keepCompleteMatch {
newMatches = append(newMatches, match)
continue
}
// drop failed match
currentMatchRune := match.body[currentRunePosition-match.start]
if !s.initialismRuneEqual(currentMatchRune, currentRune) {
continue
}
// try to complete ongoing match
if currentRunePosition-match.start == len(match.body)-1 {
// we are close; the next step is to check the symbol ahead
// if it is a small letter, then it is not the end of match
// but beginning of the next word
if currentRunePosition < len(nameRunes)-1 {
nextRune := nameRunes[currentRunePosition+1]
if newWord := unicode.IsLower(nextRune); newWord {
// oh ok, it was the start of a new word
continue
}
if matches != nil { // skip first iteration
for _, match := range *matches {
if keepCompleteMatch := match.complete; keepCompleteMatch {
*newMatches = append(*newMatches, match)
continue
}
match.complete = true
match.end = currentRunePosition
}
// drop failed match
currentMatchRune := match.body[currentRunePosition-match.start]
if currentMatchRune != currentRune {
continue
}
newMatches = append(newMatches, match)
// try to complete ongoing match
if currentRunePosition-match.start == len(match.body)-1 {
// we are close; the next step is to check the symbol ahead
// if it is a small letter, then it is not the end of match
// but beginning of the next word
if currentRunePosition < len(nameRunes)-1 {
nextRune := nameRunes[currentRunePosition+1]
if newWord := unicode.IsLower(nextRune); newWord {
// oh ok, it was the start of a new word
continue
}
}
match.complete = true
match.end = currentRunePosition
}
*newMatches = append(*newMatches, match)
}
}
// check for new initialism matches
for _, initialism := range s.initialisms {
initialismRunes := []rune(initialism)
if s.initialismRuneEqual(initialismRunes[0], currentRune) {
newMatches = append(newMatches, &initialismMatch{
for i := range s.initialisms {
initialismRunes := s.initialismsRunes[i]
if initialismRunes[0] == currentRune {
*newMatches = append(*newMatches, initialismMatch{
start: currentRunePosition,
body: initialismRunes,
complete: false,
@@ -140,24 +285,28 @@ func (s *splitter) gatherInitialismMatches(nameRunes []rune) initialismMatches {
}
}
if matches != nil {
poolOfMatches.RedeemMatches(matches)
}
matches = newMatches
}
// up to the caller to redeem this last slice
return matches
}
func (s *splitter) mapMatchesToNameLexems(nameRunes []rune, matches initialismMatches) []nameLexem {
nameLexems := make([]nameLexem, 0)
func (s splitter) mapMatchesToNameLexems(nameRunes []rune, matches *initialismMatches) *[]nameLexem {
nameLexems := poolOfLexems.BorrowLexems()
var lastAcceptedMatch *initialismMatch
for _, match := range matches {
var lastAcceptedMatch initialismMatch
for _, match := range *matches {
if !match.complete {
continue
}
if firstMatch := lastAcceptedMatch == nil; firstMatch {
nameLexems = append(nameLexems, s.breakCasualString(nameRunes[:match.start])...)
nameLexems = append(nameLexems, s.breakInitialism(string(match.body)))
if firstMatch := lastAcceptedMatch.isZero(); firstMatch {
s.appendBrokenDownCasualString(nameLexems, nameRunes[:match.start])
*nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
lastAcceptedMatch = match
@@ -169,63 +318,66 @@ func (s *splitter) mapMatchesToNameLexems(nameRunes []rune, matches initialismMa
}
middle := nameRunes[lastAcceptedMatch.end+1 : match.start]
nameLexems = append(nameLexems, s.breakCasualString(middle)...)
nameLexems = append(nameLexems, s.breakInitialism(string(match.body)))
s.appendBrokenDownCasualString(nameLexems, middle)
*nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
lastAcceptedMatch = match
}
// we have not found any accepted matches
if lastAcceptedMatch == nil {
return s.breakCasualString(nameRunes)
if lastAcceptedMatch.isZero() {
*nameLexems = (*nameLexems)[:0]
s.appendBrokenDownCasualString(nameLexems, nameRunes)
} else if lastAcceptedMatch.end+1 != len(nameRunes) {
rest := nameRunes[lastAcceptedMatch.end+1:]
s.appendBrokenDownCasualString(nameLexems, rest)
}
if lastAcceptedMatch.end+1 != len(nameRunes) {
rest := nameRunes[lastAcceptedMatch.end+1:]
nameLexems = append(nameLexems, s.breakCasualString(rest)...)
}
poolOfMatches.RedeemMatches(matches)
return nameLexems
}
func (s *splitter) initialismRuneEqual(a, b rune) bool {
return a == b
}
func (s *splitter) breakInitialism(original string) nameLexem {
func (s splitter) breakInitialism(original string) nameLexem {
return newInitialismNameLexem(original, original)
}
func (s *splitter) breakCasualString(str []rune) []nameLexem {
segments := make([]nameLexem, 0)
currentSegment := ""
func (s splitter) appendBrokenDownCasualString(segments *[]nameLexem, str []rune) {
currentSegment := poolOfBuffers.BorrowBuffer(len(str)) // unlike strings.Builder, bytes.Buffer initial storage can reused
defer func() {
poolOfBuffers.RedeemBuffer(currentSegment)
}()
addCasualNameLexem := func(original string) {
segments = append(segments, newCasualNameLexem(original))
*segments = append(*segments, newCasualNameLexem(original))
}
addInitialismNameLexem := func(original, match string) {
segments = append(segments, newInitialismNameLexem(original, match))
*segments = append(*segments, newInitialismNameLexem(original, match))
}
addNameLexem := func(original string) {
if s.postSplitInitialismCheck {
for _, initialism := range s.initialisms {
if upper(initialism) == upper(original) {
addInitialismNameLexem(original, initialism)
var addNameLexem func(string)
if s.postSplitInitialismCheck {
addNameLexem = func(original string) {
for i := range s.initialisms {
if isEqualFoldIgnoreSpace(s.initialismsUpperCased[i], original) {
addInitialismNameLexem(original, s.initialisms[i])
return
}
}
}
addCasualNameLexem(original)
addCasualNameLexem(original)
}
} else {
addNameLexem = addCasualNameLexem
}
for _, rn := range string(str) {
if replace, found := nameReplaceTable[rn]; found {
if currentSegment != "" {
addNameLexem(currentSegment)
currentSegment = ""
for _, rn := range str {
if replace, found := nameReplaceTable(rn); found {
if currentSegment.Len() > 0 {
addNameLexem(currentSegment.String())
currentSegment.Reset()
}
if replace != "" {
@@ -236,27 +388,121 @@ func (s *splitter) breakCasualString(str []rune) []nameLexem {
}
if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) {
if currentSegment != "" {
addNameLexem(currentSegment)
currentSegment = ""
if currentSegment.Len() > 0 {
addNameLexem(currentSegment.String())
currentSegment.Reset()
}
continue
}
if unicode.IsUpper(rn) {
if currentSegment != "" {
addNameLexem(currentSegment)
if currentSegment.Len() > 0 {
addNameLexem(currentSegment.String())
}
currentSegment = ""
currentSegment.Reset()
}
currentSegment += string(rn)
currentSegment.WriteRune(rn)
}
if currentSegment != "" {
addNameLexem(currentSegment)
if currentSegment.Len() > 0 {
addNameLexem(currentSegment.String())
}
return segments
}
// isEqualFoldIgnoreSpace is the same as strings.EqualFold, but
// it ignores leading and trailing blank spaces in the compared
// string.
//
// base is assumed to be composed of upper-cased runes, and be already
// trimmed.
//
// This code is heavily inspired from strings.EqualFold.
func isEqualFoldIgnoreSpace(base []rune, str string) bool {
var i, baseIndex int
// equivalent to b := []byte(str), but without data copy
b := hackStringBytes(str)
for i < len(b) {
if c := b[i]; c < utf8.RuneSelf {
// fast path for ASCII
if c != ' ' && c != '\t' {
break
}
i++
continue
}
// unicode case
r, size := utf8.DecodeRune(b[i:])
if !unicode.IsSpace(r) {
break
}
i += size
}
if i >= len(b) {
return len(base) == 0
}
for _, baseRune := range base {
if i >= len(b) {
break
}
if c := b[i]; c < utf8.RuneSelf {
// single byte rune case (ASCII)
if baseRune >= utf8.RuneSelf {
return false
}
baseChar := byte(baseRune)
if c != baseChar &&
!('a' <= c && c <= 'z' && c-'a'+'A' == baseChar) {
return false
}
baseIndex++
i++
continue
}
// unicode case
r, size := utf8.DecodeRune(b[i:])
if unicode.ToUpper(r) != baseRune {
return false
}
baseIndex++
i += size
}
if baseIndex != len(base) {
return false
}
// all passed: now we should only have blanks
for i < len(b) {
if c := b[i]; c < utf8.RuneSelf {
// fast path for ASCII
if c != ' ' && c != '\t' {
return false
}
i++
continue
}
// unicode case
r, size := utf8.DecodeRune(b[i:])
if !unicode.IsSpace(r) {
return false
}
i += size
}
return true
}

8
vendor/github.com/go-openapi/swag/string_bytes.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
package swag
import "unsafe"
// hackStringBytes returns the (unsafe) underlying bytes slice of a string.
func hackStringBytes(str string) []byte {
return unsafe.Slice(unsafe.StringData(str), len(str))
}

View File

@@ -18,76 +18,25 @@ import (
"reflect"
"strings"
"unicode"
"unicode/utf8"
)
// commonInitialisms are common acronyms that are kept as whole uppercased words.
var commonInitialisms *indexOfInitialisms
// initialisms is a slice of sorted initialisms
var initialisms []string
var isInitialism func(string) bool
// GoNamePrefixFunc sets an optional rule to prefix go names
// which do not start with a letter.
//
// The prefix function is assumed to return a string that starts with an upper case letter.
//
// e.g. to help convert "123" into "{prefix}123"
//
// The default is to prefix with "X"
var GoNamePrefixFunc func(string) string
func init() {
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
var configuredInitialisms = map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTPS": true,
"HTTP": true,
"ID": true,
"IP": true,
"IPv4": true,
"IPv6": true,
"JSON": true,
"LHS": true,
"OAI": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
func prefixFunc(name, in string) string {
if GoNamePrefixFunc == nil {
return "X" + in
}
// a thread-safe index of initialisms
commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
initialisms = commonInitialisms.sorted()
// a test function
isInitialism = commonInitialisms.isInitialism
return GoNamePrefixFunc(name) + in
}
const (
@@ -156,25 +105,9 @@ func SplitByFormat(data, format string) []string {
return result
}
type byInitialism []string
func (s byInitialism) Len() int {
return len(s)
}
func (s byInitialism) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s byInitialism) Less(i, j int) bool {
if len(s[i]) != len(s[j]) {
return len(s[i]) < len(s[j])
}
return strings.Compare(s[i], s[j]) > 0
}
// Removes leading whitespaces
func trim(str string) string {
return strings.Trim(str, " ")
return strings.TrimSpace(str)
}
// Shortcut to strings.ToUpper()
@@ -188,15 +121,20 @@ func lower(str string) string {
}
// Camelize an uppercased word
func Camelize(word string) (camelized string) {
func Camelize(word string) string {
camelized := poolOfBuffers.BorrowBuffer(len(word))
defer func() {
poolOfBuffers.RedeemBuffer(camelized)
}()
for pos, ru := range []rune(word) {
if pos > 0 {
camelized += string(unicode.ToLower(ru))
camelized.WriteRune(unicode.ToLower(ru))
} else {
camelized += string(unicode.ToUpper(ru))
camelized.WriteRune(unicode.ToUpper(ru))
}
}
return
return camelized.String()
}
// ToFileName lowercases and underscores a go type name
@@ -224,33 +162,40 @@ func ToCommandName(name string) string {
// ToHumanNameLower represents a code name as a human series of words
func ToHumanNameLower(name string) string {
in := newSplitter(withPostSplitInitialismCheck).split(name)
out := make([]string, 0, len(in))
s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
in := s.split(name)
poolOfSplitters.RedeemSplitter(s)
out := make([]string, 0, len(*in))
for _, w := range in {
for _, w := range *in {
if !w.IsInitialism() {
out = append(out, lower(w.GetOriginal()))
} else {
out = append(out, w.GetOriginal())
out = append(out, trim(w.GetOriginal()))
}
}
poolOfLexems.RedeemLexems(in)
return strings.Join(out, " ")
}
// ToHumanNameTitle represents a code name as a human series of words with the first letters titleized
func ToHumanNameTitle(name string) string {
in := newSplitter(withPostSplitInitialismCheck).split(name)
s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
in := s.split(name)
poolOfSplitters.RedeemSplitter(s)
out := make([]string, 0, len(in))
for _, w := range in {
original := w.GetOriginal()
out := make([]string, 0, len(*in))
for _, w := range *in {
original := trim(w.GetOriginal())
if !w.IsInitialism() {
out = append(out, Camelize(original))
} else {
out = append(out, original)
}
}
poolOfLexems.RedeemLexems(in)
return strings.Join(out, " ")
}
@@ -264,7 +209,7 @@ func ToJSONName(name string) string {
out = append(out, lower(w))
continue
}
out = append(out, Camelize(w))
out = append(out, Camelize(trim(w)))
}
return strings.Join(out, "")
}
@@ -283,35 +228,70 @@ func ToVarName(name string) string {
// ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes
func ToGoName(name string) string {
lexems := newSplitter(withPostSplitInitialismCheck).split(name)
s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
lexems := s.split(name)
poolOfSplitters.RedeemSplitter(s)
defer func() {
poolOfLexems.RedeemLexems(lexems)
}()
lexemes := *lexems
result := ""
for _, lexem := range lexems {
if len(lexemes) == 0 {
return ""
}
result := poolOfBuffers.BorrowBuffer(len(name))
defer func() {
poolOfBuffers.RedeemBuffer(result)
}()
// check if not starting with a letter, upper case
firstPart := lexemes[0].GetUnsafeGoName()
if lexemes[0].IsInitialism() {
firstPart = upper(firstPart)
}
if c := firstPart[0]; c < utf8.RuneSelf {
// ASCII
switch {
case 'A' <= c && c <= 'Z':
result.WriteString(firstPart)
case 'a' <= c && c <= 'z':
result.WriteByte(c - 'a' + 'A')
result.WriteString(firstPart[1:])
default:
result.WriteString(prefixFunc(name, firstPart))
// NOTE: no longer check if prefixFunc returns a string that starts with uppercase:
// assume this is always the case
}
} else {
// unicode
firstRune, _ := utf8.DecodeRuneInString(firstPart)
switch {
case !unicode.IsLetter(firstRune):
result.WriteString(prefixFunc(name, firstPart))
case !unicode.IsUpper(firstRune):
result.WriteString(prefixFunc(name, firstPart))
/*
result.WriteRune(unicode.ToUpper(firstRune))
result.WriteString(firstPart[offset:])
*/
default:
result.WriteString(firstPart)
}
}
for _, lexem := range lexemes[1:] {
goName := lexem.GetUnsafeGoName()
// to support old behavior
if lexem.IsInitialism() {
goName = upper(goName)
}
result += goName
result.WriteString(goName)
}
if len(result) > 0 {
// Only prefix with X when the first character isn't an ascii letter
first := []rune(result)[0]
if !unicode.IsLetter(first) || (first > unicode.MaxASCII && !unicode.IsUpper(first)) {
if GoNamePrefixFunc == nil {
return "X" + result
}
result = GoNamePrefixFunc(name) + result
}
first = []rune(result)[0]
if unicode.IsLetter(first) && !unicode.IsUpper(first) {
result = string(append([]rune{unicode.ToUpper(first)}, []rune(result)[1:]...))
}
}
return result
return result.String()
}
// ContainsStrings searches a slice of strings for a case-sensitive match
@@ -343,7 +323,7 @@ type zeroable interface {
func IsZero(data interface{}) bool {
v := reflect.ValueOf(data)
// check for nil data
switch v.Kind() {
switch v.Kind() { //nolint:exhaustive
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if v.IsNil() {
return true
@@ -356,7 +336,7 @@ func IsZero(data interface{}) bool {
}
// continue with slightly more complex reflection
switch v.Kind() {
switch v.Kind() { //nolint:exhaustive
case reflect.String:
return v.Len() == 0
case reflect.Bool:
@@ -376,16 +356,6 @@ func IsZero(data interface{}) bool {
}
}
// AddInitialisms add additional initialisms
func AddInitialisms(words ...string) {
for _, word := range words {
// commonInitialisms[upper(word)] = true
commonInitialisms.add(upper(word))
}
// sort again
initialisms = commonInitialisms.sorted()
}
// CommandLineOptionsGroup represents a group of user-defined command line options
type CommandLineOptionsGroup struct {
ShortDescription string

View File

@@ -16,8 +16,11 @@ package swag
import (
"encoding/json"
"errors"
"fmt"
"path/filepath"
"reflect"
"sort"
"strconv"
"github.com/mailru/easyjson/jlexer"
@@ -48,7 +51,7 @@ func BytesToYAMLDoc(data []byte) (interface{}, error) {
return nil, err
}
if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
return nil, fmt.Errorf("only YAML documents that are objects are supported")
return nil, errors.New("only YAML documents that are objects are supported")
}
return &document, nil
}
@@ -147,7 +150,7 @@ func yamlScalar(node *yaml.Node) (interface{}, error) {
case yamlTimestamp:
return node.Value, nil
case yamlNull:
return nil, nil
return nil, nil //nolint:nilnil
default:
return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag())
}
@@ -245,7 +248,27 @@ func (s JSONMapSlice) MarshalYAML() (interface{}, error) {
return yaml.Marshal(&n)
}
func isNil(input interface{}) bool {
if input == nil {
return true
}
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
func json2yaml(item interface{}) (*yaml.Node, error) {
if isNil(item) {
return &yaml.Node{
Kind: yaml.ScalarNode,
Value: "null",
}, nil
}
switch val := item.(type) {
case JSONMapSlice:
var n yaml.Node
@@ -265,7 +288,14 @@ func json2yaml(item interface{}) (*yaml.Node, error) {
case map[string]interface{}:
var n yaml.Node
n.Kind = yaml.MappingNode
for k, v := range val {
keys := make([]string, 0, len(val))
for k := range val {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := val[k]
childNode, err := json2yaml(v)
if err != nil {
return nil, err
@@ -318,8 +348,9 @@ func json2yaml(item interface{}) (*yaml.Node, error) {
Tag: yamlBoolScalar,
Value: strconv.FormatBool(val),
}, nil
default:
return nil, fmt.Errorf("unhandled type: %T", val)
}
return nil, nil
}
// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice

View File

@@ -1,191 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -1,133 +0,0 @@
/*
Copyright 2013 Google Inc.
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 lru implements an LRU cache.
package lru
import "container/list"
// Cache is an LRU cache. It is not safe for concurrent access.
type Cache struct {
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
MaxEntries int
// OnEvicted optionally specifies a callback function to be
// executed when an entry is purged from the cache.
OnEvicted func(key Key, value interface{})
ll *list.List
cache map[interface{}]*list.Element
}
// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
type Key interface{}
type entry struct {
key Key
value interface{}
}
// New creates a new Cache.
// If maxEntries is zero, the cache has no limit and it's assumed
// that eviction is done by the caller.
func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
ll: list.New(),
cache: make(map[interface{}]*list.Element),
}
}
// Add adds a value to the cache.
func (c *Cache) Add(key Key, value interface{}) {
if c.cache == nil {
c.cache = make(map[interface{}]*list.Element)
c.ll = list.New()
}
if ee, ok := c.cache[key]; ok {
c.ll.MoveToFront(ee)
ee.Value.(*entry).value = value
return
}
ele := c.ll.PushFront(&entry{key, value})
c.cache[key] = ele
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
c.RemoveOldest()
}
}
// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.ll.MoveToFront(ele)
return ele.Value.(*entry).value, true
}
return
}
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key Key) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
c.removeElement(ele)
}
}
// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
if c.cache == nil {
return
}
ele := c.ll.Back()
if ele != nil {
c.removeElement(ele)
}
}
func (c *Cache) removeElement(e *list.Element) {
c.ll.Remove(e)
kv := e.Value.(*entry)
delete(c.cache, kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
// Len returns the number of items in the cache.
func (c *Cache) Len() int {
if c.cache == nil {
return 0
}
return c.ll.Len()
}
// Clear purges all stored items from the cache.
func (c *Cache) Clear() {
if c.OnEvicted != nil {
for _, e := range c.cache {
kv := e.Value.(*entry)
c.OnEvicted(kv.key, kv.value)
}
}
c.ll = nil
c.cache = nil
}

1
vendor/github.com/google/btree/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1 @@
language: go

202
vendor/github.com/google/btree/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

12
vendor/github.com/google/btree/README.md generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# BTree implementation for Go
![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master)
This package provides an in-memory B-Tree implementation for Go, useful as
an ordered, mutable data structure.
The API is based off of the wonderful
http://godoc.org/github.com/petar/GoLLRB/llrb, and is meant to allow btree to
act as a drop-in replacement for gollrb trees.
See http://godoc.org/github.com/google/btree for documentation.

890
vendor/github.com/google/btree/btree.go generated vendored Normal file
View File

@@ -0,0 +1,890 @@
// Copyright 2014 Google Inc.
//
// 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 btree implements in-memory B-Trees of arbitrary degree.
//
// btree implements an in-memory B-Tree for use as an ordered data structure.
// It is not meant for persistent storage solutions.
//
// It has a flatter structure than an equivalent red-black or other binary tree,
// which in some cases yields better memory usage and/or performance.
// See some discussion on the matter here:
// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html
// Note, though, that this project is in no way related to the C++ B-Tree
// implementation written about there.
//
// Within this tree, each node contains a slice of items and a (possibly nil)
// slice of children. For basic numeric values or raw structs, this can cause
// efficiency differences when compared to equivalent C++ template code that
// stores values in arrays within the node:
// * Due to the overhead of storing values as interfaces (each
// value needs to be stored as the value itself, then 2 words for the
// interface pointing to that value and its type), resulting in higher
// memory use.
// * Since interfaces can point to values anywhere in memory, values are
// most likely not stored in contiguous blocks, resulting in a higher
// number of cache misses.
// These issues don't tend to matter, though, when working with strings or other
// heap-allocated structures, since C++-equivalent structures also must store
// pointers and also distribute their values across the heap.
//
// This implementation is designed to be a drop-in replacement to gollrb.LLRB
// trees, (http://github.com/petar/gollrb), an excellent and probably the most
// widely used ordered tree implementation in the Go ecosystem currently.
// Its functions, therefore, exactly mirror those of
// llrb.LLRB where possible. Unlike gollrb, though, we currently don't
// support storing multiple equivalent values.
package btree
import (
"fmt"
"io"
"sort"
"strings"
"sync"
)
// Item represents a single object in the tree.
type Item interface {
// Less tests whether the current item is less than the given argument.
//
// This must provide a strict weak ordering.
// If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only
// hold one of either a or b in the tree).
Less(than Item) bool
}
const (
DefaultFreeListSize = 32
)
var (
nilItems = make(items, 16)
nilChildren = make(children, 16)
)
// FreeList represents a free list of btree nodes. By default each
// BTree has its own FreeList, but multiple BTrees can share the same
// FreeList.
// Two Btrees using the same freelist are safe for concurrent write access.
type FreeList struct {
mu sync.Mutex
freelist []*node
}
// NewFreeList creates a new free list.
// size is the maximum size of the returned free list.
func NewFreeList(size int) *FreeList {
return &FreeList{freelist: make([]*node, 0, size)}
}
func (f *FreeList) newNode() (n *node) {
f.mu.Lock()
index := len(f.freelist) - 1
if index < 0 {
f.mu.Unlock()
return new(node)
}
n = f.freelist[index]
f.freelist[index] = nil
f.freelist = f.freelist[:index]
f.mu.Unlock()
return
}
// freeNode adds the given node to the list, returning true if it was added
// and false if it was discarded.
func (f *FreeList) freeNode(n *node) (out bool) {
f.mu.Lock()
if len(f.freelist) < cap(f.freelist) {
f.freelist = append(f.freelist, n)
out = true
}
f.mu.Unlock()
return
}
// ItemIterator allows callers of Ascend* to iterate in-order over portions of
// the tree. When this function returns false, iteration will stop and the
// associated Ascend* function will immediately return.
type ItemIterator func(i Item) bool
// New creates a new B-Tree with the given degree.
//
// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
// and 2-4 children).
func New(degree int) *BTree {
return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize))
}
// NewWithFreeList creates a new B-Tree that uses the given node free list.
func NewWithFreeList(degree int, f *FreeList) *BTree {
if degree <= 1 {
panic("bad degree")
}
return &BTree{
degree: degree,
cow: &copyOnWriteContext{freelist: f},
}
}
// items stores items in a node.
type items []Item
// insertAt inserts a value into the given index, pushing all subsequent values
// forward.
func (s *items) insertAt(index int, item Item) {
*s = append(*s, nil)
if index < len(*s) {
copy((*s)[index+1:], (*s)[index:])
}
(*s)[index] = item
}
// removeAt removes a value at a given index, pulling all subsequent values
// back.
func (s *items) removeAt(index int) Item {
item := (*s)[index]
copy((*s)[index:], (*s)[index+1:])
(*s)[len(*s)-1] = nil
*s = (*s)[:len(*s)-1]
return item
}
// pop removes and returns the last element in the list.
func (s *items) pop() (out Item) {
index := len(*s) - 1
out = (*s)[index]
(*s)[index] = nil
*s = (*s)[:index]
return
}
// truncate truncates this instance at index so that it contains only the
// first index items. index must be less than or equal to length.
func (s *items) truncate(index int) {
var toClear items
*s, toClear = (*s)[:index], (*s)[index:]
for len(toClear) > 0 {
toClear = toClear[copy(toClear, nilItems):]
}
}
// find returns the index where the given item should be inserted into this
// list. 'found' is true if the item already exists in the list at the given
// index.
func (s items) find(item Item) (index int, found bool) {
i := sort.Search(len(s), func(i int) bool {
return item.Less(s[i])
})
if i > 0 && !s[i-1].Less(item) {
return i - 1, true
}
return i, false
}
// children stores child nodes in a node.
type children []*node
// insertAt inserts a value into the given index, pushing all subsequent values
// forward.
func (s *children) insertAt(index int, n *node) {
*s = append(*s, nil)
if index < len(*s) {
copy((*s)[index+1:], (*s)[index:])
}
(*s)[index] = n
}
// removeAt removes a value at a given index, pulling all subsequent values
// back.
func (s *children) removeAt(index int) *node {
n := (*s)[index]
copy((*s)[index:], (*s)[index+1:])
(*s)[len(*s)-1] = nil
*s = (*s)[:len(*s)-1]
return n
}
// pop removes and returns the last element in the list.
func (s *children) pop() (out *node) {
index := len(*s) - 1
out = (*s)[index]
(*s)[index] = nil
*s = (*s)[:index]
return
}
// truncate truncates this instance at index so that it contains only the
// first index children. index must be less than or equal to length.
func (s *children) truncate(index int) {
var toClear children
*s, toClear = (*s)[:index], (*s)[index:]
for len(toClear) > 0 {
toClear = toClear[copy(toClear, nilChildren):]
}
}
// node is an internal node in a tree.
//
// It must at all times maintain the invariant that either
// * len(children) == 0, len(items) unconstrained
// * len(children) == len(items) + 1
type node struct {
items items
children children
cow *copyOnWriteContext
}
func (n *node) mutableFor(cow *copyOnWriteContext) *node {
if n.cow == cow {
return n
}
out := cow.newNode()
if cap(out.items) >= len(n.items) {
out.items = out.items[:len(n.items)]
} else {
out.items = make(items, len(n.items), cap(n.items))
}
copy(out.items, n.items)
// Copy children
if cap(out.children) >= len(n.children) {
out.children = out.children[:len(n.children)]
} else {
out.children = make(children, len(n.children), cap(n.children))
}
copy(out.children, n.children)
return out
}
func (n *node) mutableChild(i int) *node {
c := n.children[i].mutableFor(n.cow)
n.children[i] = c
return c
}
// split splits the given node at the given index. The current node shrinks,
// and this function returns the item that existed at that index and a new node
// containing all items/children after it.
func (n *node) split(i int) (Item, *node) {
item := n.items[i]
next := n.cow.newNode()
next.items = append(next.items, n.items[i+1:]...)
n.items.truncate(i)
if len(n.children) > 0 {
next.children = append(next.children, n.children[i+1:]...)
n.children.truncate(i + 1)
}
return item, next
}
// maybeSplitChild checks if a child should be split, and if so splits it.
// Returns whether or not a split occurred.
func (n *node) maybeSplitChild(i, maxItems int) bool {
if len(n.children[i].items) < maxItems {
return false
}
first := n.mutableChild(i)
item, second := first.split(maxItems / 2)
n.items.insertAt(i, item)
n.children.insertAt(i+1, second)
return true
}
// insert inserts an item into the subtree rooted at this node, making sure
// no nodes in the subtree exceed maxItems items. Should an equivalent item be
// be found/replaced by insert, it will be returned.
func (n *node) insert(item Item, maxItems int) Item {
i, found := n.items.find(item)
if found {
out := n.items[i]
n.items[i] = item
return out
}
if len(n.children) == 0 {
n.items.insertAt(i, item)
return nil
}
if n.maybeSplitChild(i, maxItems) {
inTree := n.items[i]
switch {
case item.Less(inTree):
// no change, we want first split node
case inTree.Less(item):
i++ // we want second split node
default:
out := n.items[i]
n.items[i] = item
return out
}
}
return n.mutableChild(i).insert(item, maxItems)
}
// get finds the given key in the subtree and returns it.
func (n *node) get(key Item) Item {
i, found := n.items.find(key)
if found {
return n.items[i]
} else if len(n.children) > 0 {
return n.children[i].get(key)
}
return nil
}
// min returns the first item in the subtree.
func min(n *node) Item {
if n == nil {
return nil
}
for len(n.children) > 0 {
n = n.children[0]
}
if len(n.items) == 0 {
return nil
}
return n.items[0]
}
// max returns the last item in the subtree.
func max(n *node) Item {
if n == nil {
return nil
}
for len(n.children) > 0 {
n = n.children[len(n.children)-1]
}
if len(n.items) == 0 {
return nil
}
return n.items[len(n.items)-1]
}
// toRemove details what item to remove in a node.remove call.
type toRemove int
const (
removeItem toRemove = iota // removes the given item
removeMin // removes smallest item in the subtree
removeMax // removes largest item in the subtree
)
// remove removes an item from the subtree rooted at this node.
func (n *node) remove(item Item, minItems int, typ toRemove) Item {
var i int
var found bool
switch typ {
case removeMax:
if len(n.children) == 0 {
return n.items.pop()
}
i = len(n.items)
case removeMin:
if len(n.children) == 0 {
return n.items.removeAt(0)
}
i = 0
case removeItem:
i, found = n.items.find(item)
if len(n.children) == 0 {
if found {
return n.items.removeAt(i)
}
return nil
}
default:
panic("invalid type")
}
// If we get to here, we have children.
if len(n.children[i].items) <= minItems {
return n.growChildAndRemove(i, item, minItems, typ)
}
child := n.mutableChild(i)
// Either we had enough items to begin with, or we've done some
// merging/stealing, because we've got enough now and we're ready to return
// stuff.
if found {
// The item exists at index 'i', and the child we've selected can give us a
// predecessor, since if we've gotten here it's got > minItems items in it.
out := n.items[i]
// We use our special-case 'remove' call with typ=maxItem to pull the
// predecessor of item i (the rightmost leaf of our immediate left child)
// and set it into where we pulled the item from.
n.items[i] = child.remove(nil, minItems, removeMax)
return out
}
// Final recursive call. Once we're here, we know that the item isn't in this
// node and that the child is big enough to remove from.
return child.remove(item, minItems, typ)
}
// growChildAndRemove grows child 'i' to make sure it's possible to remove an
// item from it while keeping it at minItems, then calls remove to actually
// remove it.
//
// Most documentation says we have to do two sets of special casing:
// 1) item is in this node
// 2) item is in child
// In both cases, we need to handle the two subcases:
// A) node has enough values that it can spare one
// B) node doesn't have enough values
// For the latter, we have to check:
// a) left sibling has node to spare
// b) right sibling has node to spare
// c) we must merge
// To simplify our code here, we handle cases #1 and #2 the same:
// If a node doesn't have enough items, we make sure it does (using a,b,c).
// We then simply redo our remove call, and the second time (regardless of
// whether we're in case 1 or 2), we'll have enough items and can guarantee
// that we hit case A.
func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item {
if i > 0 && len(n.children[i-1].items) > minItems {
// Steal from left child
child := n.mutableChild(i)
stealFrom := n.mutableChild(i - 1)
stolenItem := stealFrom.items.pop()
child.items.insertAt(0, n.items[i-1])
n.items[i-1] = stolenItem
if len(stealFrom.children) > 0 {
child.children.insertAt(0, stealFrom.children.pop())
}
} else if i < len(n.items) && len(n.children[i+1].items) > minItems {
// steal from right child
child := n.mutableChild(i)
stealFrom := n.mutableChild(i + 1)
stolenItem := stealFrom.items.removeAt(0)
child.items = append(child.items, n.items[i])
n.items[i] = stolenItem
if len(stealFrom.children) > 0 {
child.children = append(child.children, stealFrom.children.removeAt(0))
}
} else {
if i >= len(n.items) {
i--
}
child := n.mutableChild(i)
// merge with right child
mergeItem := n.items.removeAt(i)
mergeChild := n.children.removeAt(i + 1)
child.items = append(child.items, mergeItem)
child.items = append(child.items, mergeChild.items...)
child.children = append(child.children, mergeChild.children...)
n.cow.freeNode(mergeChild)
}
return n.remove(item, minItems, typ)
}
type direction int
const (
descend = direction(-1)
ascend = direction(+1)
)
// iterate provides a simple method for iterating over elements in the tree.
//
// When ascending, the 'start' should be less than 'stop' and when descending,
// the 'start' should be greater than 'stop'. Setting 'includeStart' to true
// will force the iterator to include the first item when it equals 'start',
// thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a
// "greaterThan" or "lessThan" queries.
func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator) (bool, bool) {
var ok, found bool
var index int
switch dir {
case ascend:
if start != nil {
index, _ = n.items.find(start)
}
for i := index; i < len(n.items); i++ {
if len(n.children) > 0 {
if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok {
return hit, false
}
}
if !includeStart && !hit && start != nil && !start.Less(n.items[i]) {
hit = true
continue
}
hit = true
if stop != nil && !n.items[i].Less(stop) {
return hit, false
}
if !iter(n.items[i]) {
return hit, false
}
}
if len(n.children) > 0 {
if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
return hit, false
}
}
case descend:
if start != nil {
index, found = n.items.find(start)
if !found {
index = index - 1
}
} else {
index = len(n.items) - 1
}
for i := index; i >= 0; i-- {
if start != nil && !n.items[i].Less(start) {
if !includeStart || hit || start.Less(n.items[i]) {
continue
}
}
if len(n.children) > 0 {
if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
return hit, false
}
}
if stop != nil && !stop.Less(n.items[i]) {
return hit, false // continue
}
hit = true
if !iter(n.items[i]) {
return hit, false
}
}
if len(n.children) > 0 {
if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok {
return hit, false
}
}
}
return hit, true
}
// Used for testing/debugging purposes.
func (n *node) print(w io.Writer, level int) {
fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items)
for _, c := range n.children {
c.print(w, level+1)
}
}
// BTree is an implementation of a B-Tree.
//
// BTree stores Item instances in an ordered structure, allowing easy insertion,
// removal, and iteration.
//
// Write operations are not safe for concurrent mutation by multiple
// goroutines, but Read operations are.
type BTree struct {
degree int
length int
root *node
cow *copyOnWriteContext
}
// copyOnWriteContext pointers determine node ownership... a tree with a write
// context equivalent to a node's write context is allowed to modify that node.
// A tree whose write context does not match a node's is not allowed to modify
// it, and must create a new, writable copy (IE: it's a Clone).
//
// When doing any write operation, we maintain the invariant that the current
// node's context is equal to the context of the tree that requested the write.
// We do this by, before we descend into any node, creating a copy with the
// correct context if the contexts don't match.
//
// Since the node we're currently visiting on any write has the requesting
// tree's context, that node is modifiable in place. Children of that node may
// not share context, but before we descend into them, we'll make a mutable
// copy.
type copyOnWriteContext struct {
freelist *FreeList
}
// Clone clones the btree, lazily. Clone should not be called concurrently,
// but the original tree (t) and the new tree (t2) can be used concurrently
// once the Clone call completes.
//
// The internal tree structure of b is marked read-only and shared between t and
// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
// whenever one of b's original nodes would have been modified. Read operations
// should have no performance degredation. Write operations for both t and t2
// will initially experience minor slow-downs caused by additional allocs and
// copies due to the aforementioned copy-on-write logic, but should converge to
// the original performance characteristics of the original tree.
func (t *BTree) Clone() (t2 *BTree) {
// Create two entirely new copy-on-write contexts.
// This operation effectively creates three trees:
// the original, shared nodes (old b.cow)
// the new b.cow nodes
// the new out.cow nodes
cow1, cow2 := *t.cow, *t.cow
out := *t
t.cow = &cow1
out.cow = &cow2
return &out
}
// maxItems returns the max number of items to allow per node.
func (t *BTree) maxItems() int {
return t.degree*2 - 1
}
// minItems returns the min number of items to allow per node (ignored for the
// root node).
func (t *BTree) minItems() int {
return t.degree - 1
}
func (c *copyOnWriteContext) newNode() (n *node) {
n = c.freelist.newNode()
n.cow = c
return
}
type freeType int
const (
ftFreelistFull freeType = iota // node was freed (available for GC, not stored in freelist)
ftStored // node was stored in the freelist for later use
ftNotOwned // node was ignored by COW, since it's owned by another one
)
// freeNode frees a node within a given COW context, if it's owned by that
// context. It returns what happened to the node (see freeType const
// documentation).
func (c *copyOnWriteContext) freeNode(n *node) freeType {
if n.cow == c {
// clear to allow GC
n.items.truncate(0)
n.children.truncate(0)
n.cow = nil
if c.freelist.freeNode(n) {
return ftStored
} else {
return ftFreelistFull
}
} else {
return ftNotOwned
}
}
// ReplaceOrInsert adds the given item to the tree. If an item in the tree
// already equals the given one, it is removed from the tree and returned.
// Otherwise, nil is returned.
//
// nil cannot be added to the tree (will panic).
func (t *BTree) ReplaceOrInsert(item Item) Item {
if item == nil {
panic("nil item being added to BTree")
}
if t.root == nil {
t.root = t.cow.newNode()
t.root.items = append(t.root.items, item)
t.length++
return nil
} else {
t.root = t.root.mutableFor(t.cow)
if len(t.root.items) >= t.maxItems() {
item2, second := t.root.split(t.maxItems() / 2)
oldroot := t.root
t.root = t.cow.newNode()
t.root.items = append(t.root.items, item2)
t.root.children = append(t.root.children, oldroot, second)
}
}
out := t.root.insert(item, t.maxItems())
if out == nil {
t.length++
}
return out
}
// Delete removes an item equal to the passed in item from the tree, returning
// it. If no such item exists, returns nil.
func (t *BTree) Delete(item Item) Item {
return t.deleteItem(item, removeItem)
}
// DeleteMin removes the smallest item in the tree and returns it.
// If no such item exists, returns nil.
func (t *BTree) DeleteMin() Item {
return t.deleteItem(nil, removeMin)
}
// DeleteMax removes the largest item in the tree and returns it.
// If no such item exists, returns nil.
func (t *BTree) DeleteMax() Item {
return t.deleteItem(nil, removeMax)
}
func (t *BTree) deleteItem(item Item, typ toRemove) Item {
if t.root == nil || len(t.root.items) == 0 {
return nil
}
t.root = t.root.mutableFor(t.cow)
out := t.root.remove(item, t.minItems(), typ)
if len(t.root.items) == 0 && len(t.root.children) > 0 {
oldroot := t.root
t.root = t.root.children[0]
t.cow.freeNode(oldroot)
}
if out != nil {
t.length--
}
return out
}
// AscendRange calls the iterator for every value in the tree within the range
// [greaterOrEqual, lessThan), until iterator returns false.
func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(ascend, greaterOrEqual, lessThan, true, false, iterator)
}
// AscendLessThan calls the iterator for every value in the tree within the range
// [first, pivot), until iterator returns false.
func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(ascend, nil, pivot, false, false, iterator)
}
// AscendGreaterOrEqual calls the iterator for every value in the tree within
// the range [pivot, last], until iterator returns false.
func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(ascend, pivot, nil, true, false, iterator)
}
// Ascend calls the iterator for every value in the tree within the range
// [first, last], until iterator returns false.
func (t *BTree) Ascend(iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(ascend, nil, nil, false, false, iterator)
}
// DescendRange calls the iterator for every value in the tree within the range
// [lessOrEqual, greaterThan), until iterator returns false.
func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(descend, lessOrEqual, greaterThan, true, false, iterator)
}
// DescendLessOrEqual calls the iterator for every value in the tree within the range
// [pivot, first], until iterator returns false.
func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(descend, pivot, nil, true, false, iterator)
}
// DescendGreaterThan calls the iterator for every value in the tree within
// the range [last, pivot), until iterator returns false.
func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(descend, nil, pivot, false, false, iterator)
}
// Descend calls the iterator for every value in the tree within the range
// [last, first], until iterator returns false.
func (t *BTree) Descend(iterator ItemIterator) {
if t.root == nil {
return
}
t.root.iterate(descend, nil, nil, false, false, iterator)
}
// Get looks for the key item in the tree, returning it. It returns nil if
// unable to find that item.
func (t *BTree) Get(key Item) Item {
if t.root == nil {
return nil
}
return t.root.get(key)
}
// Min returns the smallest item in the tree, or nil if the tree is empty.
func (t *BTree) Min() Item {
return min(t.root)
}
// Max returns the largest item in the tree, or nil if the tree is empty.
func (t *BTree) Max() Item {
return max(t.root)
}
// Has returns true if the given key is in the tree.
func (t *BTree) Has(key Item) bool {
return t.Get(key) != nil
}
// Len returns the number of items currently in the tree.
func (t *BTree) Len() int {
return t.length
}
// Clear removes all items from the btree. If addNodesToFreelist is true,
// t's nodes are added to its freelist as part of this call, until the freelist
// is full. Otherwise, the root node is simply dereferenced and the subtree
// left to Go's normal GC processes.
//
// This can be much faster
// than calling Delete on all elements, because that requires finding/removing
// each element in the tree and updating the tree accordingly. It also is
// somewhat faster than creating a new tree to replace the old one, because
// nodes from the old tree are reclaimed into the freelist for use by the new
// one, instead of being lost to the garbage collector.
//
// This call takes:
// O(1): when addNodesToFreelist is false, this is a single operation.
// O(1): when the freelist is already full, it breaks out immediately
// O(freelist size): when the freelist is empty and the nodes are all owned
// by this tree, nodes are added to the freelist until full.
// O(tree size): when all nodes are owned by another tree, all nodes are
// iterated over looking for nodes to add to the freelist, and due to
// ownership, none are.
func (t *BTree) Clear(addNodesToFreelist bool) {
if t.root != nil && addNodesToFreelist {
t.root.reset(t.cow)
}
t.root, t.length = nil, 0
}
// reset returns a subtree to the freelist. It breaks out immediately if the
// freelist is full, since the only benefit of iterating is to fill that
// freelist up. Returns true if parent reset call should continue.
func (n *node) reset(c *copyOnWriteContext) bool {
for _, child := range n.children {
if !child.reset(c) {
return false
}
}
return c.freeNode(n) != ftFreelistFull
}
// Int implements the Item interface for integers.
type Int int
// Less returns true if int(a) < int(b).
func (a Int) Less(b Item) bool {
return a < b.(Int)
}

View File

@@ -39,6 +39,7 @@ go_library(
"//common/types/traits:go_default_library",
"//interpreter:go_default_library",
"//parser:go_default_library",
"@dev_cel_expr//:expr",
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
@@ -81,7 +82,6 @@ go_test(
"//test:go_default_library",
"//test/proto2pb:go_default_library",
"//test/proto3pb:go_default_library",
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//encoding/prototext:go_default_library",

View File

@@ -23,6 +23,7 @@ import (
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
celpb "cel.dev/expr"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
@@ -312,20 +313,34 @@ func ExprTypeToType(t *exprpb.Type) (*Type, error) {
// ExprDeclToDeclaration converts a protobuf CEL declaration to a CEL-native declaration, either a Variable or Function.
func ExprDeclToDeclaration(d *exprpb.Decl) (EnvOption, error) {
return AlphaProtoAsDeclaration(d)
}
// AlphaProtoAsDeclaration converts a v1alpha1.Decl value describing a variable or function into an EnvOption.
func AlphaProtoAsDeclaration(d *exprpb.Decl) (EnvOption, error) {
canonical := &celpb.Decl{}
if err := convertProto(d, canonical); err != nil {
return nil, err
}
return ProtoAsDeclaration(canonical)
}
// ProtoAsDeclaration converts a canonical celpb.Decl value describing a variable or function into an EnvOption.
func ProtoAsDeclaration(d *celpb.Decl) (EnvOption, error) {
switch d.GetDeclKind().(type) {
case *exprpb.Decl_Function:
case *celpb.Decl_Function:
overloads := d.GetFunction().GetOverloads()
opts := make([]FunctionOpt, len(overloads))
for i, o := range overloads {
args := make([]*Type, len(o.GetParams()))
for j, p := range o.GetParams() {
a, err := types.ExprTypeToType(p)
a, err := types.ProtoAsType(p)
if err != nil {
return nil, err
}
args[j] = a
}
res, err := types.ExprTypeToType(o.GetResultType())
res, err := types.ProtoAsType(o.GetResultType())
if err != nil {
return nil, err
}
@@ -336,15 +351,15 @@ func ExprDeclToDeclaration(d *exprpb.Decl) (EnvOption, error) {
}
}
return Function(d.GetName(), opts...), nil
case *exprpb.Decl_Ident:
t, err := types.ExprTypeToType(d.GetIdent().GetType())
case *celpb.Decl_Ident:
t, err := types.ProtoAsType(d.GetIdent().GetType())
if err != nil {
return nil, err
}
if d.GetIdent().GetValue() == nil {
return Variable(d.GetName(), t), nil
}
val, err := ast.ConstantToVal(d.GetIdent().GetValue())
val, err := ast.ProtoConstantAsVal(d.GetIdent().GetValue())
if err != nil {
return nil, err
}

View File

@@ -44,6 +44,9 @@ type Ast struct {
// NativeRep converts the AST to a Go-native representation.
func (ast *Ast) NativeRep() *celast.AST {
if ast == nil {
return nil
}
return ast.impl
}
@@ -55,16 +58,13 @@ func (ast *Ast) Expr() *exprpb.Expr {
if ast == nil {
return nil
}
pbExpr, _ := celast.ExprToProto(ast.impl.Expr())
pbExpr, _ := celast.ExprToProto(ast.NativeRep().Expr())
return pbExpr
}
// IsChecked returns whether the Ast value has been successfully type-checked.
func (ast *Ast) IsChecked() bool {
if ast == nil {
return false
}
return ast.impl.IsChecked()
return ast.NativeRep().IsChecked()
}
// SourceInfo returns character offset and newline position information about expression elements.
@@ -72,7 +72,7 @@ func (ast *Ast) SourceInfo() *exprpb.SourceInfo {
if ast == nil {
return nil
}
pbInfo, _ := celast.SourceInfoToProto(ast.impl.SourceInfo())
pbInfo, _ := celast.SourceInfoToProto(ast.NativeRep().SourceInfo())
return pbInfo
}
@@ -95,7 +95,7 @@ func (ast *Ast) OutputType() *Type {
if ast == nil {
return types.ErrorType
}
return ast.impl.GetType(ast.impl.Expr().ID())
return ast.NativeRep().GetType(ast.NativeRep().Expr().ID())
}
// Source returns a view of the input used to create the Ast. This source may be complete or
@@ -218,12 +218,12 @@ func (e *Env) Check(ast *Ast) (*Ast, *Issues) {
if err != nil {
errs := common.NewErrors(ast.Source())
errs.ReportError(common.NoLocation, err.Error())
return nil, NewIssuesWithSourceInfo(errs, ast.impl.SourceInfo())
return nil, NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
}
checked, errs := checker.Check(ast.impl, ast.Source(), chk)
checked, errs := checker.Check(ast.NativeRep(), ast.Source(), chk)
if len(errs.GetErrors()) > 0 {
return nil, NewIssuesWithSourceInfo(errs, ast.impl.SourceInfo())
return nil, NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
}
// Manually create the Ast to ensure that the Ast source information (which may be more
// detailed than the information provided by Check), is returned to the caller.
@@ -244,7 +244,7 @@ func (e *Env) Check(ast *Ast) (*Ast, *Issues) {
}
}
// Apply additional validators on the type-checked result.
iss := NewIssuesWithSourceInfo(errs, ast.impl.SourceInfo())
iss := NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
for _, v := range e.validators {
v.Validate(e, vConfig, checked, iss)
}
@@ -309,17 +309,13 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
copy(chkOptsCopy, e.chkOpts)
// Copy the declarations if needed.
varsCopy := []*decls.VariableDecl{}
if chk != nil {
// If the type-checker has already been instantiated, then the e.declarations have been
// validated within the chk instance.
chkOptsCopy = append(chkOptsCopy, checker.ValidatedDeclarations(chk))
} else {
// If the type-checker has not been instantiated, ensure the unvalidated declarations are
// provided to the extended Env instance.
varsCopy = make([]*decls.VariableDecl, len(e.variables))
copy(varsCopy, e.variables)
}
varsCopy := make([]*decls.VariableDecl, len(e.variables))
copy(varsCopy, e.variables)
// Copy macros and program options
macsCopy := make([]parser.Macro, len(e.macros))
@@ -416,6 +412,17 @@ func (e *Env) Libraries() []string {
return libraries
}
// HasFunction returns whether a specific function has been configured in the environment
func (e *Env) HasFunction(functionName string) bool {
_, ok := e.functions[functionName]
return ok
}
// Functions returns map of Functions, keyed by function name, that have been configured in the environment.
func (e *Env) Functions() map[string]*decls.FunctionDecl {
return e.functions
}
// HasValidator returns whether a specific ASTValidator has been configured in the environment.
func (e *Env) HasValidator(name string) bool {
for _, v := range e.validators {
@@ -452,6 +459,12 @@ func (e *Env) ParseSource(src Source) (*Ast, *Issues) {
// Program generates an evaluable instance of the Ast within the environment (Env).
func (e *Env) Program(ast *Ast, opts ...ProgramOption) (Program, error) {
return e.PlanProgram(ast.NativeRep(), opts...)
}
// PlanProgram generates an evaluable instance of the AST in the go-native representation within
// the environment (Env).
func (e *Env) PlanProgram(a *celast.AST, opts ...ProgramOption) (Program, error) {
optSet := e.progOpts
if len(opts) != 0 {
mergedOpts := []ProgramOption{}
@@ -459,7 +472,7 @@ func (e *Env) Program(ast *Ast, opts ...ProgramOption) (Program, error) {
mergedOpts = append(mergedOpts, opts...)
optSet = mergedOpts
}
return newProgram(e, ast, optSet)
return newProgram(e, a, optSet)
}
// CELTypeAdapter returns the `types.Adapter` configured for the environment.
@@ -753,10 +766,10 @@ func (i *Issues) Append(other *Issues) *Issues {
if i == nil {
return other
}
if other == nil {
if other == nil || i == other {
return i
}
return NewIssues(i.errs.Append(other.errs.GetErrors()))
return NewIssuesWithSourceInfo(i.errs.Append(other.errs.GetErrors()), i.info)
}
// String converts the issues to a suitable display string.
@@ -790,7 +803,7 @@ type interopCELTypeProvider struct {
// FindStructType returns a types.Type instance for the given fully-qualified typeName if one exists.
//
// This method proxies to the underyling ref.TypeProvider's FindType method and converts protobuf type
// This method proxies to the underlying ref.TypeProvider's FindType method and converts protobuf type
// into a native type representation. If the conversion fails, the type is listed as not found.
func (p *interopCELTypeProvider) FindStructType(typeName string) (*types.Type, bool) {
if et, found := p.FindType(typeName); found {
@@ -813,7 +826,7 @@ func (p *interopCELTypeProvider) FindStructFieldNames(typeName string) ([]string
// FindStructFieldType returns a types.FieldType instance for the given fully-qualified typeName and field
// name, if one exists.
//
// This method proxies to the underyling ref.TypeProvider's FindFieldType method and converts protobuf type
// This method proxies to the underlying ref.TypeProvider's FindFieldType method and converts protobuf type
// into a native type representation. If the conversion fails, the type is listed as not found.
func (p *interopCELTypeProvider) FindStructFieldType(structType, fieldName string) (*types.FieldType, bool) {
if ft, found := p.FindFieldType(structType, fieldName); found {

View File

@@ -28,6 +28,7 @@ import (
"github.com/google/cel-go/common/types/traits"
"github.com/google/cel-go/parser"
celpb "cel.dev/expr"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
anypb "google.golang.org/protobuf/types/known/anypb"
)
@@ -104,72 +105,86 @@ func AstToString(a *Ast) (string, error) {
// RefValueToValue converts between ref.Val and api.expr.Value.
// The result Value is the serialized proto form. The ref.Val must not be error or unknown.
func RefValueToValue(res ref.Val) (*exprpb.Value, error) {
return ValueAsAlphaProto(res)
}
func ValueAsAlphaProto(res ref.Val) (*exprpb.Value, error) {
canonical, err := ValueAsProto(res)
if err != nil {
return nil, err
}
alpha := &exprpb.Value{}
err = convertProto(canonical, alpha)
return alpha, err
}
func ValueAsProto(res ref.Val) (*celpb.Value, error) {
switch res.Type() {
case types.BoolType:
return &exprpb.Value{
Kind: &exprpb.Value_BoolValue{BoolValue: res.Value().(bool)}}, nil
return &celpb.Value{
Kind: &celpb.Value_BoolValue{BoolValue: res.Value().(bool)}}, nil
case types.BytesType:
return &exprpb.Value{
Kind: &exprpb.Value_BytesValue{BytesValue: res.Value().([]byte)}}, nil
return &celpb.Value{
Kind: &celpb.Value_BytesValue{BytesValue: res.Value().([]byte)}}, nil
case types.DoubleType:
return &exprpb.Value{
Kind: &exprpb.Value_DoubleValue{DoubleValue: res.Value().(float64)}}, nil
return &celpb.Value{
Kind: &celpb.Value_DoubleValue{DoubleValue: res.Value().(float64)}}, nil
case types.IntType:
return &exprpb.Value{
Kind: &exprpb.Value_Int64Value{Int64Value: res.Value().(int64)}}, nil
return &celpb.Value{
Kind: &celpb.Value_Int64Value{Int64Value: res.Value().(int64)}}, nil
case types.ListType:
l := res.(traits.Lister)
sz := l.Size().(types.Int)
elts := make([]*exprpb.Value, 0, int64(sz))
elts := make([]*celpb.Value, 0, int64(sz))
for i := types.Int(0); i < sz; i++ {
v, err := RefValueToValue(l.Get(i))
v, err := ValueAsProto(l.Get(i))
if err != nil {
return nil, err
}
elts = append(elts, v)
}
return &exprpb.Value{
Kind: &exprpb.Value_ListValue{
ListValue: &exprpb.ListValue{Values: elts}}}, nil
return &celpb.Value{
Kind: &celpb.Value_ListValue{
ListValue: &celpb.ListValue{Values: elts}}}, nil
case types.MapType:
mapper := res.(traits.Mapper)
sz := mapper.Size().(types.Int)
entries := make([]*exprpb.MapValue_Entry, 0, int64(sz))
entries := make([]*celpb.MapValue_Entry, 0, int64(sz))
for it := mapper.Iterator(); it.HasNext().(types.Bool); {
k := it.Next()
v := mapper.Get(k)
kv, err := RefValueToValue(k)
kv, err := ValueAsProto(k)
if err != nil {
return nil, err
}
vv, err := RefValueToValue(v)
vv, err := ValueAsProto(v)
if err != nil {
return nil, err
}
entries = append(entries, &exprpb.MapValue_Entry{Key: kv, Value: vv})
entries = append(entries, &celpb.MapValue_Entry{Key: kv, Value: vv})
}
return &exprpb.Value{
Kind: &exprpb.Value_MapValue{
MapValue: &exprpb.MapValue{Entries: entries}}}, nil
return &celpb.Value{
Kind: &celpb.Value_MapValue{
MapValue: &celpb.MapValue{Entries: entries}}}, nil
case types.NullType:
return &exprpb.Value{
Kind: &exprpb.Value_NullValue{}}, nil
return &celpb.Value{
Kind: &celpb.Value_NullValue{}}, nil
case types.StringType:
return &exprpb.Value{
Kind: &exprpb.Value_StringValue{StringValue: res.Value().(string)}}, nil
return &celpb.Value{
Kind: &celpb.Value_StringValue{StringValue: res.Value().(string)}}, nil
case types.TypeType:
typeName := res.(ref.Type).TypeName()
return &exprpb.Value{Kind: &exprpb.Value_TypeValue{TypeValue: typeName}}, nil
return &celpb.Value{Kind: &celpb.Value_TypeValue{TypeValue: typeName}}, nil
case types.UintType:
return &exprpb.Value{
Kind: &exprpb.Value_Uint64Value{Uint64Value: res.Value().(uint64)}}, nil
return &celpb.Value{
Kind: &celpb.Value_Uint64Value{Uint64Value: res.Value().(uint64)}}, nil
default:
any, err := res.ConvertToNative(anyPbType)
if err != nil {
return nil, err
}
return &exprpb.Value{
Kind: &exprpb.Value_ObjectValue{ObjectValue: any.(*anypb.Any)}}, nil
return &celpb.Value{
Kind: &celpb.Value_ObjectValue{ObjectValue: any.(*anypb.Any)}}, nil
}
}
@@ -192,55 +207,67 @@ var (
// ValueToRefValue converts between exprpb.Value and ref.Val.
func ValueToRefValue(adapter types.Adapter, v *exprpb.Value) (ref.Val, error) {
return AlphaProtoAsValue(adapter, v)
}
func AlphaProtoAsValue(adapter types.Adapter, v *exprpb.Value) (ref.Val, error) {
canonical := &celpb.Value{}
if err := convertProto(v, canonical); err != nil {
return nil, err
}
return ProtoAsValue(adapter, canonical)
}
func ProtoAsValue(adapter types.Adapter, v *celpb.Value) (ref.Val, error) {
switch v.Kind.(type) {
case *exprpb.Value_NullValue:
case *celpb.Value_NullValue:
return types.NullValue, nil
case *exprpb.Value_BoolValue:
case *celpb.Value_BoolValue:
return types.Bool(v.GetBoolValue()), nil
case *exprpb.Value_Int64Value:
case *celpb.Value_Int64Value:
return types.Int(v.GetInt64Value()), nil
case *exprpb.Value_Uint64Value:
case *celpb.Value_Uint64Value:
return types.Uint(v.GetUint64Value()), nil
case *exprpb.Value_DoubleValue:
case *celpb.Value_DoubleValue:
return types.Double(v.GetDoubleValue()), nil
case *exprpb.Value_StringValue:
case *celpb.Value_StringValue:
return types.String(v.GetStringValue()), nil
case *exprpb.Value_BytesValue:
case *celpb.Value_BytesValue:
return types.Bytes(v.GetBytesValue()), nil
case *exprpb.Value_ObjectValue:
case *celpb.Value_ObjectValue:
any := v.GetObjectValue()
msg, err := anypb.UnmarshalNew(any, proto.UnmarshalOptions{DiscardUnknown: true})
if err != nil {
return nil, err
}
return adapter.NativeToValue(msg), nil
case *exprpb.Value_MapValue:
case *celpb.Value_MapValue:
m := v.GetMapValue()
entries := make(map[ref.Val]ref.Val)
for _, entry := range m.Entries {
key, err := ValueToRefValue(adapter, entry.Key)
key, err := ProtoAsValue(adapter, entry.Key)
if err != nil {
return nil, err
}
pb, err := ValueToRefValue(adapter, entry.Value)
pb, err := ProtoAsValue(adapter, entry.Value)
if err != nil {
return nil, err
}
entries[key] = pb
}
return adapter.NativeToValue(entries), nil
case *exprpb.Value_ListValue:
case *celpb.Value_ListValue:
l := v.GetListValue()
elts := make([]ref.Val, len(l.Values))
for i, e := range l.Values {
rv, err := ValueToRefValue(adapter, e)
rv, err := ProtoAsValue(adapter, e)
if err != nil {
return nil, err
}
elts[i] = rv
}
return adapter.NativeToValue(elts), nil
case *exprpb.Value_TypeValue:
case *celpb.Value_TypeValue:
typeName := v.GetTypeValue()
tv, ok := typeNameToTypeValue[typeName]
if ok {
@@ -250,3 +277,12 @@ func ValueToRefValue(adapter types.Adapter, v *exprpb.Value) (ref.Val, error) {
}
return nil, errors.New("unknown value")
}
func convertProto(src, dst proto.Message) error {
pb, err := proto.Marshal(src)
if err != nil {
return err
}
err = proto.Unmarshal(pb, dst)
return err
}

View File

@@ -403,7 +403,7 @@ func optMap(meh MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *
meh.NewList(),
unusedIterVar,
varName,
meh.NewMemberCall(valueFunc, target),
meh.NewMemberCall(valueFunc, meh.Copy(target)),
meh.NewLiteral(types.False),
meh.NewIdent(varName),
mapExpr,
@@ -430,7 +430,7 @@ func optFlatMap(meh MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Exp
meh.NewList(),
unusedIterVar,
varName,
meh.NewMemberCall(valueFunc, target),
meh.NewMemberCall(valueFunc, meh.Copy(target)),
meh.NewLiteral(types.False),
meh.NewIdent(varName),
mapExpr,
@@ -446,6 +446,12 @@ func enableOptionalSyntax() EnvOption {
}
}
// EnableErrorOnBadPresenceTest enables error generation when a presence test or optional field
// selection is performed on a primitive type.
func EnableErrorOnBadPresenceTest(value bool) EnvOption {
return features(featureEnableErrorOnBadPresenceTest, value)
}
func decorateOptionalOr(i interpreter.Interpretable) (interpreter.Interpretable, error) {
call, ok := i.(interpreter.InterpretableCall)
if !ok {

View File

@@ -15,6 +15,8 @@
package cel
import (
"sort"
"github.com/google/cel-go/common"
"github.com/google/cel-go/common/ast"
"github.com/google/cel-go/common/types"
@@ -98,14 +100,21 @@ func (opt *StaticOptimizer) Optimize(env *Env, a *Ast) (*Ast, *Issues) {
// that the ids within the expression correspond to the ids within macros.
func normalizeIDs(idGen ast.IDGenerator, optimized ast.Expr, info *ast.SourceInfo) {
optimized.RenumberIDs(idGen)
if len(info.MacroCalls()) == 0 {
return
}
// Sort the macro ids to make sure that the renumbering of macro-specific variables
// is stable across normalization calls.
sortedMacroIDs := []int64{}
for id := range info.MacroCalls() {
sortedMacroIDs = append(sortedMacroIDs, id)
}
sort.Slice(sortedMacroIDs, func(i, j int) bool { return sortedMacroIDs[i] < sortedMacroIDs[j] })
// First, update the macro call ids themselves.
callIDMap := map[int64]int64{}
for id := range info.MacroCalls() {
for _, id := range sortedMacroIDs {
callIDMap[id] = idGen(id)
}
// Then update the macro call definitions which refer to these ids, but
@@ -116,7 +125,8 @@ func normalizeIDs(idGen ast.IDGenerator, optimized ast.Expr, info *ast.SourceInf
call ast.Expr
}
macroUpdates := []macroUpdate{}
for oldID, newID := range callIDMap {
for _, oldID := range sortedMacroIDs {
newID := callIDMap[oldID]
call, found := info.GetMacroCall(oldID)
if !found {
continue
@@ -134,6 +144,7 @@ func cleanupMacroRefs(expr ast.Expr, info *ast.SourceInfo) {
if len(info.MacroCalls()) == 0 {
return
}
// Sanitize the macro call references once the optimized expression has been computed
// and the ids normalized between the expression and the macros.
exprRefMap := make(map[int64]struct{})
@@ -200,6 +211,16 @@ type OptimizerContext struct {
*Issues
}
// ExtendEnv auguments the context's environment with the additional options.
func (opt *OptimizerContext) ExtendEnv(opts ...EnvOption) error {
e, err := opt.Env.Extend(opts...)
if err != nil {
return err
}
opt.Env = e
return nil
}
// ASTOptimizer applies an optimization over an AST and returns the optimized result.
type ASTOptimizer interface {
// Optimize optimizes a type-checked AST within an Environment and accumulates any issues.
@@ -253,6 +274,11 @@ func (opt *optimizerExprFactory) SetMacroCall(id int64, expr ast.Expr) {
opt.sourceInfo.SetMacroCall(id, expr)
}
// MacroCalls returns the map of macro calls currently in the context.
func (opt *optimizerExprFactory) MacroCalls() map[int64]ast.Expr {
return opt.sourceInfo.MacroCalls()
}
// NewBindMacro creates an AST expression representing the expanded bind() macro, and a macro expression
// representing the unexpanded call signature to be inserted into the source info macro call metadata.
func (opt *optimizerExprFactory) NewBindMacro(macroID int64, varName string, varInit, remaining ast.Expr) (astExpr, macroExpr ast.Expr) {

View File

@@ -61,6 +61,10 @@ const (
// compressing the logic graph to a single call when multiple like-operator
// expressions occur: e.g. a && b && c && d -> call(_&&_, [a, b, c, d])
featureVariadicLogicalASTs
// Enable error generation when a presence test or optional field selection is
// performed on a primitive type.
featureEnableErrorOnBadPresenceTest
)
// EnvOption is a functional interface for configuring the environment.
@@ -243,6 +247,13 @@ func Abbrevs(qualifiedNames ...string) EnvOption {
}
}
// customTypeRegistry is an internal-only interface containing the minimum methods required to support
// custom types. It is a subset of methods from ref.TypeRegistry.
type customTypeRegistry interface {
RegisterDescriptor(protoreflect.FileDescriptor) error
RegisterType(...ref.Type) error
}
// Types adds one or more type declarations to the environment, allowing for construction of
// type-literals whose definitions are included in the common expression built-in set.
//
@@ -255,12 +266,7 @@ func Abbrevs(qualifiedNames ...string) EnvOption {
// Note: This option must be specified after the CustomTypeProvider option when used together.
func Types(addTypes ...any) EnvOption {
return func(e *Env) (*Env, error) {
var reg ref.TypeRegistry
var isReg bool
reg, isReg = e.provider.(*types.Registry)
if !isReg {
reg, isReg = e.provider.(ref.TypeRegistry)
}
reg, isReg := e.provider.(customTypeRegistry)
if !isReg {
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
}
@@ -297,7 +303,7 @@ func Types(addTypes ...any) EnvOption {
// extension or by re-using the same EnvOption with another NewEnv() call.
func TypeDescs(descs ...any) EnvOption {
return func(e *Env) (*Env, error) {
reg, isReg := e.provider.(ref.TypeRegistry)
reg, isReg := e.provider.(customTypeRegistry)
if !isReg {
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
}
@@ -345,7 +351,7 @@ func TypeDescs(descs ...any) EnvOption {
}
}
func registerFileSet(reg ref.TypeRegistry, fileSet *descpb.FileDescriptorSet) error {
func registerFileSet(reg customTypeRegistry, fileSet *descpb.FileDescriptorSet) error {
files, err := protodesc.NewFiles(fileSet)
if err != nil {
return fmt.Errorf("protodesc.NewFiles(%v) failed: %v", fileSet, err)
@@ -353,7 +359,7 @@ func registerFileSet(reg ref.TypeRegistry, fileSet *descpb.FileDescriptorSet) er
return registerFiles(reg, files)
}
func registerFiles(reg ref.TypeRegistry, files *protoregistry.Files) error {
func registerFiles(reg customTypeRegistry, files *protoregistry.Files) error {
var err error
files.RangeFiles(func(fd protoreflect.FileDescriptor) bool {
err = reg.RegisterDescriptor(fd)

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"sync"
"github.com/google/cel-go/common/ast"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter"
@@ -151,7 +152,7 @@ func (p *prog) clone() *prog {
// ProgramOption values.
//
// If the program cannot be configured the prog will be nil, with a non-nil error response.
func newProgram(e *Env, a *Ast, opts []ProgramOption) (Program, error) {
func newProgram(e *Env, a *ast.AST, opts []ProgramOption) (Program, error) {
// Build the dispatcher, interpreter, and default program value.
disp := interpreter.NewDispatcher()
@@ -187,10 +188,13 @@ func newProgram(e *Env, a *Ast, opts []ProgramOption) (Program, error) {
// Set the attribute factory after the options have been set.
var attrFactory interpreter.AttributeFactory
attrFactorOpts := []interpreter.AttrFactoryOption{
interpreter.EnableErrorOnBadPresenceTest(p.HasFeature(featureEnableErrorOnBadPresenceTest)),
}
if p.evalOpts&OptPartialEval == OptPartialEval {
attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider)
attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...)
} else {
attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider)
attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...)
}
interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, attrFactory)
p.interpreter = interp
@@ -252,9 +256,9 @@ func newProgram(e *Env, a *Ast, opts []ProgramOption) (Program, error) {
return p.initInterpretable(a, decorators)
}
func (p *prog) initInterpretable(a *Ast, decs []interpreter.InterpretableDecorator) (*prog, error) {
func (p *prog) initInterpretable(a *ast.AST, decs []interpreter.InterpretableDecorator) (*prog, error) {
// When the AST has been exprAST it contains metadata that can be used to speed up program execution.
interpretable, err := p.interpreter.NewInterpretable(a.impl, decs...)
interpretable, err := p.interpreter.NewInterpretable(a, decs...)
if err != nil {
return nil, err
}

View File

@@ -16,7 +16,6 @@ go_library(
"options.go",
"printer.go",
"scopes.go",
"standard.go",
"types.go",
],
importpath = "github.com/google/cel-go/checker",

View File

@@ -496,16 +496,32 @@ func (c *checker) checkComprehension(e ast.Expr) {
comp := e.AsComprehension()
c.check(comp.IterRange())
c.check(comp.AccuInit())
accuType := c.getType(comp.AccuInit())
rangeType := substitute(c.mappings, c.getType(comp.IterRange()), false)
var varType *types.Type
// Create a scope for the comprehension since it has a local accumulation variable.
// This scope will contain the accumulation variable used to compute the result.
accuType := c.getType(comp.AccuInit())
c.env = c.env.enterScope()
c.env.AddIdents(decls.NewVariable(comp.AccuVar(), accuType))
var varType, var2Type *types.Type
switch rangeType.Kind() {
case types.ListKind:
// varType represents the list element type for one-variable comprehensions.
varType = rangeType.Parameters()[0]
if comp.HasIterVar2() {
// varType represents the list index (int) for two-variable comprehensions,
// and var2Type represents the list element type.
var2Type = varType
varType = types.IntType
}
case types.MapKind:
// Ranges over the keys.
// varType represents the map entry key for all comprehension types.
varType = rangeType.Parameters()[0]
if comp.HasIterVar2() {
// var2Type represents the map entry value for two-variable comprehensions.
var2Type = rangeType.Parameters()[1]
}
case types.DynKind, types.ErrorKind, types.TypeParamKind:
// Set the range type to DYN to prevent assignment to a potentially incorrect type
// at a later point in type-checking. The isAssignable call will update the type
@@ -518,13 +534,12 @@ func (c *checker) checkComprehension(e ast.Expr) {
varType = types.ErrorType
}
// Create a scope for the comprehension since it has a local accumulation variable.
// This scope will contain the accumulation variable used to compute the result.
c.env = c.env.enterScope()
c.env.AddIdents(decls.NewVariable(comp.AccuVar(), accuType))
// Create a block scope for the loop.
c.env = c.env.enterScope()
c.env.AddIdents(decls.NewVariable(comp.IterVar(), varType))
if comp.HasIterVar2() {
c.env.AddIdents(decls.NewVariable(comp.IterVar2(), var2Type))
}
// Check the variable references in the condition and step.
c.check(comp.LoopCondition())
c.assertType(comp.LoopCondition(), types.BoolType)

View File

@@ -1,35 +0,0 @@
// 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 checker
import (
"github.com/google/cel-go/common/stdlib"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// StandardFunctions returns the Decls for all functions in the evaluator.
//
// Deprecated: prefer stdlib.FunctionExprDecls()
func StandardFunctions() []*exprpb.Decl {
return stdlib.FunctionExprDecls()
}
// StandardTypes returns the set of type identifiers for standard library types.
//
// Deprecated: prefer stdlib.TypeExprDecls()
func StandardTypes() []*exprpb.Decl {
return stdlib.TypeExprDecls()
}

View File

@@ -18,7 +18,6 @@ go_library(
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",
],
)

View File

@@ -15,11 +15,13 @@ go_library(
"navigable.go",
],
importpath = "github.com/google/cel-go/common/ast",
deps = [
deps = [
"//common:go_default_library",
"//common/types:go_default_library",
"//common/types/ref:go_default_library",
"@dev_cel_expr//:expr",
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
],
)
@@ -35,12 +37,13 @@ go_test(
embed = [
":go_default_library",
],
deps = [
deps = [
"//checker:go_default_library",
"//checker/decls:go_default_library",
"//common:go_default_library",
"//common/containers:go_default_library",
"//common/decls:go_default_library",
"//common/operators:go_default_library",
"//common/overloads:go_default_library",
"//common/stdlib:go_default_library",
"//common/types:go_default_library",

View File

@@ -310,21 +310,18 @@ func (s *SourceInfo) SetOffsetRange(id int64, o OffsetRange) {
s.offsetRanges[id] = o
}
// ClearOffsetRange removes the OffsetRange for the given expression id.
func (s *SourceInfo) ClearOffsetRange(id int64) {
if s != nil {
delete(s.offsetRanges, id)
}
}
// GetStartLocation calculates the human-readable 1-based line and 0-based column of the first character
// of the expression node at the id.
func (s *SourceInfo) GetStartLocation(id int64) common.Location {
if o, found := s.GetOffsetRange(id); found {
line := 1
col := int(o.Start)
for _, lineOffset := range s.LineOffsets() {
if lineOffset < o.Start {
line++
col = int(o.Start - lineOffset)
} else {
break
}
}
return common.NewLocation(line, col)
return s.GetLocationByOffset(o.Start)
}
return common.NoLocation
}
@@ -336,21 +333,25 @@ func (s *SourceInfo) GetStartLocation(id int64) common.Location {
// be identical to the start location for the expression.
func (s *SourceInfo) GetStopLocation(id int64) common.Location {
if o, found := s.GetOffsetRange(id); found {
line := 1
col := int(o.Stop)
for _, lineOffset := range s.LineOffsets() {
if lineOffset < o.Stop {
line++
col = int(o.Stop - lineOffset)
} else {
break
}
}
return common.NewLocation(line, col)
return s.GetLocationByOffset(o.Stop)
}
return common.NoLocation
}
// GetLocationByOffset returns the line and column information for a given character offset.
func (s *SourceInfo) GetLocationByOffset(offset int32) common.Location {
line := 1
col := int(offset)
for _, lineOffset := range s.LineOffsets() {
if lineOffset > offset {
break
}
line++
col = int(offset - lineOffset)
}
return common.NewLocation(line, col)
}
// ComputeOffset calculates the 0-based character offset from a 1-based line and 0-based column.
func (s *SourceInfo) ComputeOffset(line, col int32) int32 {
if s != nil {

View File

@@ -17,12 +17,14 @@ package ast
import (
"fmt"
"google.golang.org/protobuf/proto"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
structpb "google.golang.org/protobuf/types/known/structpb"
celpb "cel.dev/expr"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// ToProto converts an AST to a CheckedExpr protobouf.
@@ -173,9 +175,10 @@ func exprComprehension(factory ExprFactory, id int64, comp *exprpb.Expr_Comprehe
if err != nil {
return nil, err
}
return factory.NewComprehension(id,
return factory.NewComprehensionTwoVar(id,
iterRange,
comp.GetIterVar(),
comp.GetIterVar2(),
comp.GetAccuVar(),
accuInit,
loopCond,
@@ -363,6 +366,7 @@ func protoComprehension(id int64, comp ComprehensionExpr) (*exprpb.Expr, error)
ExprKind: &exprpb.Expr_ComprehensionExpr{
ComprehensionExpr: &exprpb.Expr_Comprehension{
IterVar: comp.IterVar(),
IterVar2: comp.IterVar2(),
IterRange: iterRange,
AccuVar: comp.AccuVar(),
AccuInit: accuInit,
@@ -609,24 +613,47 @@ func ValToConstant(v ref.Val) (*exprpb.Constant, error) {
// ConstantToVal converts a protobuf Constant to a CEL-native ref.Val.
func ConstantToVal(c *exprpb.Constant) (ref.Val, error) {
return AlphaProtoConstantAsVal(c)
}
// AlphaProtoConstantAsVal converts a v1alpha1.Constant protobuf to a CEL-native ref.Val.
func AlphaProtoConstantAsVal(c *exprpb.Constant) (ref.Val, error) {
if c == nil {
return nil, nil
}
canonical := &celpb.Constant{}
if err := convertProto(c, canonical); err != nil {
return nil, err
}
return ProtoConstantAsVal(canonical)
}
// ProtoConstantAsVal converts a canonical celpb.Constant protobuf to a CEL-native ref.Val.
func ProtoConstantAsVal(c *celpb.Constant) (ref.Val, error) {
switch c.GetConstantKind().(type) {
case *exprpb.Constant_BoolValue:
case *celpb.Constant_BoolValue:
return types.Bool(c.GetBoolValue()), nil
case *exprpb.Constant_BytesValue:
case *celpb.Constant_BytesValue:
return types.Bytes(c.GetBytesValue()), nil
case *exprpb.Constant_DoubleValue:
case *celpb.Constant_DoubleValue:
return types.Double(c.GetDoubleValue()), nil
case *exprpb.Constant_Int64Value:
case *celpb.Constant_Int64Value:
return types.Int(c.GetInt64Value()), nil
case *exprpb.Constant_NullValue:
case *celpb.Constant_NullValue:
return types.NullValue, nil
case *exprpb.Constant_StringValue:
case *celpb.Constant_StringValue:
return types.String(c.GetStringValue()), nil
case *exprpb.Constant_Uint64Value:
case *celpb.Constant_Uint64Value:
return types.Uint(c.GetUint64Value()), nil
}
return nil, fmt.Errorf("unsupported constant kind: %v", c.GetConstantKind())
}
func convertProto(src, dst proto.Message) error {
pb, err := proto.Marshal(src)
if err != nil {
return err
}
err = proto.Unmarshal(pb, dst)
return err
}

View File

@@ -158,7 +158,7 @@ type EntryExpr interface {
// IDGenerator produces unique ids suitable for tagging expression nodes
type IDGenerator func(originalID int64) int64
// CallExpr defines an interface for inspecting a function call and its arugments.
// CallExpr defines an interface for inspecting a function call and its arguments.
type CallExpr interface {
// FunctionName returns the name of the function.
FunctionName() string
@@ -269,8 +269,22 @@ type ComprehensionExpr interface {
IterRange() Expr
// IterVar returns the iteration variable name.
//
// For one-variable comprehensions, the iter var refers to the element value
// when iterating over a list, or the map key when iterating over a map.
//
// For two-variable comprehneions, the iter var refers to the list index or the
// map key.
IterVar() string
// IterVar2 returns the second iteration variable name.
//
// When the value is non-empty, the comprehension is a two-variable comprehension.
IterVar2() string
// HasIterVar2 returns true if the second iteration variable is non-empty.
HasIterVar2() bool
// AccuVar returns the accumulation variable name.
AccuVar() string
@@ -397,6 +411,7 @@ func (e *expr) SetKindCase(other Expr) {
e.exprKindCase = &baseComprehensionExpr{
iterRange: c.IterRange(),
iterVar: c.IterVar(),
iterVar2: c.IterVar2(),
accuVar: c.AccuVar(),
accuInit: c.AccuInit(),
loopCond: c.LoopCondition(),
@@ -505,6 +520,7 @@ var _ ComprehensionExpr = &baseComprehensionExpr{}
type baseComprehensionExpr struct {
iterRange Expr
iterVar string
iterVar2 string
accuVar string
accuInit Expr
loopCond Expr
@@ -527,6 +543,14 @@ func (e *baseComprehensionExpr) IterVar() string {
return e.iterVar
}
func (e *baseComprehensionExpr) IterVar2() string {
return e.iterVar2
}
func (e *baseComprehensionExpr) HasIterVar2() bool {
return e.iterVar2 != ""
}
func (e *baseComprehensionExpr) AccuVar() string {
return e.accuVar
}

View File

@@ -27,9 +27,12 @@ type ExprFactory interface {
// NewCall creates an Expr value representing a global function call.
NewCall(id int64, function string, args ...Expr) Expr
// NewComprehension creates an Expr value representing a comprehension over a value range.
// NewComprehension creates an Expr value representing a one-variable comprehension over a value range.
NewComprehension(id int64, iterRange Expr, iterVar, accuVar string, accuInit, loopCondition, loopStep, result Expr) Expr
// NewComprehensionTwoVar creates an Expr value representing a two-variable comprehension over a value range.
NewComprehensionTwoVar(id int64, iterRange Expr, iterVar, iterVar2, accuVar string, accuInit, loopCondition, loopStep, result Expr) Expr
// NewMemberCall creates an Expr value representing a member function call.
NewMemberCall(id int64, function string, receiver Expr, args ...Expr) Expr
@@ -111,11 +114,17 @@ func (fac *baseExprFactory) NewMemberCall(id int64, function string, target Expr
}
func (fac *baseExprFactory) NewComprehension(id int64, iterRange Expr, iterVar, accuVar string, accuInit, loopCond, loopStep, result Expr) Expr {
// Set the iter_var2 to empty string to indicate the second variable is omitted
return fac.NewComprehensionTwoVar(id, iterRange, iterVar, "", accuVar, accuInit, loopCond, loopStep, result)
}
func (fac *baseExprFactory) NewComprehensionTwoVar(id int64, iterRange Expr, iterVar, iterVar2, accuVar string, accuInit, loopCond, loopStep, result Expr) Expr {
return fac.newExpr(
id,
&baseComprehensionExpr{
iterRange: iterRange,
iterVar: iterVar,
iterVar2: iterVar2,
accuVar: accuVar,
accuInit: accuInit,
loopCond: loopCond,
@@ -223,9 +232,10 @@ func (fac *baseExprFactory) CopyExpr(e Expr) Expr {
return fac.NewMemberCall(e.ID(), c.FunctionName(), fac.CopyExpr(c.Target()), argsCopy...)
case ComprehensionKind:
compre := e.AsComprehension()
return fac.NewComprehension(e.ID(),
return fac.NewComprehensionTwoVar(e.ID(),
fac.CopyExpr(compre.IterRange()),
compre.IterVar(),
compre.IterVar2(),
compre.AccuVar(),
fac.CopyExpr(compre.AccuInit()),
fac.CopyExpr(compre.LoopCondition()),

View File

@@ -390,6 +390,14 @@ func (comp navigableComprehensionImpl) IterVar() string {
return comp.Expr.AsComprehension().IterVar()
}
func (comp navigableComprehensionImpl) IterVar2() string {
return comp.Expr.AsComprehension().IterVar2()
}
func (comp navigableComprehensionImpl) HasIterVar2() bool {
return comp.Expr.AsComprehension().HasIterVar2()
}
func (comp navigableComprehensionImpl) AccuVar() string {
return comp.Expr.AsComprehension().AccuVar()
}

View File

@@ -19,6 +19,7 @@ package containers
import (
"fmt"
"strings"
"unicode"
"github.com/google/cel-go/common/ast"
)
@@ -212,6 +213,13 @@ type ContainerOption func(*Container) (*Container, error)
func Abbrevs(qualifiedNames ...string) ContainerOption {
return func(c *Container) (*Container, error) {
for _, qn := range qualifiedNames {
qn = strings.TrimSpace(qn)
for _, r := range qn {
if !isIdentifierChar(r) {
return nil, fmt.Errorf(
"invalid qualified name: %s, wanted name of the form 'qualified.name'", qn)
}
}
ind := strings.LastIndex(qn, ".")
if ind <= 0 || ind >= len(qn)-1 {
return nil, fmt.Errorf(
@@ -278,6 +286,10 @@ func aliasAs(kind, qualifiedName, alias string) ContainerOption {
}
}
func isIdentifierChar(r rune) bool {
return r <= unicode.MaxASCII && (r == '.' || r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r))
}
// Name sets the fully-qualified name of the Container.
func Name(name string) ContainerOption {
return func(c *Container) (*Container, error) {

View File

@@ -215,6 +215,11 @@ func (w *debugWriter) appendComprehension(comprehension ast.ComprehensionExpr) {
w.append(comprehension.IterVar())
w.append(",")
w.appendLine()
if comprehension.HasIterVar2() {
w.append(comprehension.IterVar2())
w.append(",")
w.appendLine()
}
w.append("// Target")
w.appendLine()
w.Buffer(comprehension.IterRange())

View File

@@ -162,7 +162,9 @@ func (f *FunctionDecl) AddOverload(overload *OverloadDecl) error {
if oID == overload.ID() {
if o.SignatureEquals(overload) && o.IsNonStrict() == overload.IsNonStrict() {
// Allow redefinition of an overload implementation so long as the signatures match.
f.overloads[oID] = overload
if overload.hasBinding() {
f.overloads[oID] = overload
}
return nil
}
return fmt.Errorf("overload redefinition in function. %s: %s has multiple definitions", f.Name(), oID)
@@ -249,15 +251,15 @@ func (f *FunctionDecl) Bindings() ([]*functions.Overload, error) {
// are preserved in order to assist with the function resolution step.
switch len(args) {
case 1:
if o.unaryOp != nil && o.matchesRuntimeSignature( /* disableTypeGuards=*/ false, args...) {
if o.unaryOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
return o.unaryOp(args[0])
}
case 2:
if o.binaryOp != nil && o.matchesRuntimeSignature( /* disableTypeGuards=*/ false, args...) {
if o.binaryOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
return o.binaryOp(args[0], args[1])
}
}
if o.functionOp != nil && o.matchesRuntimeSignature( /* disableTypeGuards=*/ false, args...) {
if o.functionOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
return o.functionOp(args...)
}
// eventually this will fall through to the noSuchOverload below.
@@ -775,8 +777,13 @@ func (v *VariableDecl) DeclarationIsEquivalent(other *VariableDecl) bool {
return v.Name() == other.Name() && v.Type().IsEquivalentType(other.Type())
}
// VariableDeclToExprDecl converts a go-native variable declaration into a protobuf-type variable declaration.
func VariableDeclToExprDecl(v *VariableDecl) (*exprpb.Decl, error) {
// TypeVariable creates a new type identifier for use within a types.Provider
func TypeVariable(t *types.Type) *VariableDecl {
return NewVariable(t.TypeName(), types.NewTypeTypeWithParam(t))
}
// variableDeclToExprDecl converts a go-native variable declaration into a protobuf-type variable declaration.
func variableDeclToExprDecl(v *VariableDecl) (*exprpb.Decl, error) {
varType, err := types.TypeToExprType(v.Type())
if err != nil {
return nil, err
@@ -784,13 +791,8 @@ func VariableDeclToExprDecl(v *VariableDecl) (*exprpb.Decl, error) {
return chkdecls.NewVar(v.Name(), varType), nil
}
// TypeVariable creates a new type identifier for use within a types.Provider
func TypeVariable(t *types.Type) *VariableDecl {
return NewVariable(t.TypeName(), types.NewTypeTypeWithParam(t))
}
// FunctionDeclToExprDecl converts a go-native function declaration into a protobuf-typed function declaration.
func FunctionDeclToExprDecl(f *FunctionDecl) (*exprpb.Decl, error) {
// functionDeclToExprDecl converts a go-native function declaration into a protobuf-typed function declaration.
func functionDeclToExprDecl(f *FunctionDecl) (*exprpb.Decl, error) {
overloads := make([]*exprpb.Decl_FunctionDecl_Overload, len(f.overloads))
for i, oID := range f.overloadOrdinals {
o := f.overloads[oID]

View File

@@ -18,8 +18,6 @@ import (
"fmt"
"strings"
"unicode/utf8"
"golang.org/x/text/width"
)
// NewError creates an error associated with an expression id with the given message at the given location.
@@ -35,18 +33,15 @@ type Error struct {
}
const (
dot = "."
ind = "^"
dot = "."
ind = "^"
wideDot = "\uff0e"
wideInd = "\uff3e"
// 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",

View File

@@ -127,20 +127,48 @@ var nilBuffer = &emptyBuffer{}
// 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 {
buf, _ := newBuffer(data, false)
return buf
}
// NewBufferAndLineOffsets returns an efficient implementation of Buffer for the given text based on
// the ranges of the encoded code points contained within, as well as returning the line offsets.
//
// 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 NewBufferAndLineOffsets(data string) (Buffer, []int32) {
return newBuffer(data, true)
}
func newBuffer(data string, lines bool) (Buffer, []int32) {
if len(data) == 0 {
return nilBuffer
return nilBuffer, []int32{0}
}
var (
idx = 0
buf8 = make([]byte, 0, len(data))
idx = 0
off int32 = 0
buf8 = make([]byte, 0, len(data))
buf16 []uint16
buf32 []rune
offs []int32
)
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if lines && r == '\n' {
offs = append(offs, off+1)
}
if r < utf8.RuneSelf {
buf8 = append(buf8, byte(r))
off++
continue
}
if r <= 0xffff {
@@ -150,6 +178,7 @@ func NewBuffer(data string) Buffer {
}
buf8 = nil
buf16 = append(buf16, uint16(r))
off++
goto copy16
}
buf32 = make([]rune, len(buf8), len(data))
@@ -158,17 +187,25 @@ func NewBuffer(data string) Buffer {
}
buf8 = nil
buf32 = append(buf32, r)
off++
goto copy32
}
if lines {
offs = append(offs, off+1)
}
return &asciiBuffer{
arr: buf8,
}
}, offs
copy16:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if lines && r == '\n' {
offs = append(offs, off+1)
}
if r <= 0xffff {
buf16 = append(buf16, uint16(r))
off++
continue
}
buf32 = make([]rune, len(buf16), len(data))
@@ -177,18 +214,29 @@ copy16:
}
buf16 = nil
buf32 = append(buf32, r)
off++
goto copy32
}
if lines {
offs = append(offs, off+1)
}
return &basicBuffer{
arr: buf16,
}
}, offs
copy32:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if lines && r == '\n' {
offs = append(offs, off+1)
}
buf32 = append(buf32, r)
off++
}
if lines {
offs = append(offs, off+1)
}
return &supplementalBuffer{
arr: buf32,
}
}, offs
}

View File

@@ -15,9 +15,6 @@
package common
import (
"strings"
"unicode/utf8"
"github.com/google/cel-go/common/runes"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
@@ -80,17 +77,11 @@ func NewTextSource(text string) Source {
// 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
}
buf, offs := runes.NewBufferAndLineOffsets(contents)
return &sourceImpl{
Buffer: runes.NewBuffer(contents),
Buffer: buf,
description: description,
lineOffsets: offsets,
lineOffsets: offs,
}
}
@@ -172,9 +163,8 @@ func (s *sourceImpl) findLine(characterOffset int32) (int32, int32) {
for _, lineOffset := range s.lineOffsets {
if lineOffset > characterOffset {
break
} else {
line++
}
line++
}
if line == 1 {
return line, 0

View File

@@ -12,7 +12,6 @@ go_library(
],
importpath = "github.com/google/cel-go/common/stdlib",
deps = [
"//checker/decls:go_default_library",
"//common/decls:go_default_library",
"//common/functions:go_default_library",
"//common/operators:go_default_library",
@@ -20,6 +19,5 @@ go_library(
"//common/types:go_default_library",
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
],
)

View File

@@ -23,15 +23,11 @@ import (
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
var (
stdFunctions []*decls.FunctionDecl
stdFnDecls []*exprpb.Decl
stdTypes []*decls.VariableDecl
stdTypeDecls []*exprpb.Decl
)
func init() {
@@ -55,15 +51,6 @@ func init() {
decls.TypeVariable(types.UintType),
}
stdTypeDecls = make([]*exprpb.Decl, 0, len(stdTypes))
for _, stdType := range stdTypes {
typeVar, err := decls.VariableDeclToExprDecl(stdType)
if err != nil {
panic(err)
}
stdTypeDecls = append(stdTypeDecls, typeVar)
}
stdFunctions = []*decls.FunctionDecl{
// Logical operators. Special-cased within the interpreter.
// Note, the singleton binding prevents extensions from overriding the operator behavior.
@@ -576,18 +563,6 @@ func init() {
decls.MemberOverload(overloads.DurationToMilliseconds,
argTypes(types.DurationType), types.IntType)),
}
stdFnDecls = make([]*exprpb.Decl, 0, len(stdFunctions))
for _, fn := range stdFunctions {
if fn.IsDeclarationDisabled() {
continue
}
ed, err := decls.FunctionDeclToExprDecl(fn)
if err != nil {
panic(err)
}
stdFnDecls = append(stdFnDecls, ed)
}
}
// Functions returns the set of standard library function declarations and definitions for CEL.
@@ -595,27 +570,11 @@ func Functions() []*decls.FunctionDecl {
return stdFunctions
}
// FunctionExprDecls returns the legacy style protobuf-typed declarations for all functions and overloads
// in the CEL standard environment.
//
// Deprecated: use Functions
func FunctionExprDecls() []*exprpb.Decl {
return stdFnDecls
}
// Types returns the set of standard library types for CEL.
func Types() []*decls.VariableDecl {
return stdTypes
}
// TypeExprDecls returns the legacy style protobuf-typed declarations for all types in the CEL
// standard environment.
//
// Deprecated: use Types
func TypeExprDecls() []*exprpb.Decl {
return stdTypeDecls
}
func notStrictlyFalse(value ref.Val) ref.Val {
if types.IsBool(value) {
return value

View File

@@ -40,10 +40,12 @@ go_library(
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"@com_github_stoewer_go_strcase//:go_default_library",
"@dev_cel_expr//:expr",
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1: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/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/structpb:go_default_library",

View File

@@ -58,7 +58,17 @@ func (b Bytes) Compare(other ref.Val) ref.Val {
// ConvertToNative implements the ref.Val interface method.
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (any, error) {
switch typeDesc.Kind() {
case reflect.Array, reflect.Slice:
case reflect.Array:
if len(b) != typeDesc.Len() {
return nil, fmt.Errorf("[%d]byte not assignable to [%d]byte array", len(b), typeDesc.Len())
}
refArrPtr := reflect.New(reflect.ArrayOf(len(b), typeDesc.Elem()))
refArr := refArrPtr.Elem()
for i, byt := range b {
refArr.Index(i).Set(reflect.ValueOf(byt).Convert(typeDesc.Elem()))
}
return refArr.Interface(), nil
case reflect.Slice:
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {

View File

@@ -256,6 +256,15 @@ func (l *baseList) IsZeroValue() bool {
return l.size == 0
}
// Fold calls the FoldEntry method for each (index, value) pair in the list.
func (l *baseList) Fold(f traits.Folder) {
for i := 0; i < l.size; i++ {
if !f.FoldEntry(i, l.get(i)) {
break
}
}
}
// Iterator implements the traits.Iterable interface method.
func (l *baseList) Iterator() traits.Iterator {
return newListIterator(l)
@@ -433,6 +442,15 @@ func (l *concatList) IsZeroValue() bool {
return l.Size().(Int) == 0
}
// Fold calls the FoldEntry method for each (index, value) pair in the list.
func (l *concatList) Fold(f traits.Folder) {
for i := Int(0); i < l.Size().(Int); i++ {
if !f.FoldEntry(i, l.Get(i)) {
break
}
}
}
// Iterator implements the traits.Iterable interface method.
func (l *concatList) Iterator() traits.Iterator {
return newListIterator(l)
@@ -527,3 +545,30 @@ func IndexOrError(index ref.Val) (int, error) {
return -1, fmt.Errorf("unsupported index type '%s' in list", index.Type())
}
}
// ToFoldableList will create a Foldable version of a list suitable for key-value pair iteration.
//
// For values which are already Foldable, this call is a no-op. For all other values, the fold is
// driven via the Size() and Get() calls which means that the folding will function, but take a
// performance hit.
func ToFoldableList(l traits.Lister) traits.Foldable {
if f, ok := l.(traits.Foldable); ok {
return f
}
return interopFoldableList{Lister: l}
}
type interopFoldableList struct {
traits.Lister
}
// Fold implements the traits.Foldable interface method and performs an iteration over the
// range of elements of the list.
func (l interopFoldableList) Fold(f traits.Folder) {
sz := l.Size().(Int)
for i := Int(0); i < sz; i++ {
if !f.FoldEntry(i, l.Get(i)) {
break
}
}
}

View File

@@ -94,6 +94,24 @@ func NewProtoMap(adapter Adapter, value *pb.Map) traits.Mapper {
}
}
// NewMutableMap constructs a mutable map from an adapter and a set of map values.
func NewMutableMap(adapter Adapter, mutableValues map[ref.Val]ref.Val) traits.MutableMapper {
mutableCopy := make(map[ref.Val]ref.Val, len(mutableValues))
for k, v := range mutableValues {
mutableCopy[k] = v
}
m := &mutableMap{
baseMap: &baseMap{
Adapter: adapter,
mapAccessor: newRefValMapAccessor(mutableCopy),
value: mutableCopy,
size: len(mutableCopy),
},
mutableValues: mutableCopy,
}
return m
}
// 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.
@@ -105,6 +123,9 @@ type mapAccessor interface {
// Iterator returns an Iterator over the map key set.
Iterator() traits.Iterator
// Fold calls the FoldEntry method for each (key, value) pair in the map.
Fold(traits.Folder)
}
// baseMap is a reflection based map implementation designed to handle a variety of map-like types.
@@ -307,6 +328,28 @@ func (m *baseMap) Value() any {
return m.value
}
// mutableMap holds onto a set of mutable values which are used for intermediate computations.
type mutableMap struct {
*baseMap
mutableValues map[ref.Val]ref.Val
}
// Insert implements the traits.MutableMapper interface method, returning true if the key insertion
// succeeds.
func (m *mutableMap) Insert(k, v ref.Val) ref.Val {
if _, found := m.Find(k); found {
return NewErr("insert failed: key %v already exists", k)
}
m.mutableValues[k] = v
return m
}
// ToImmutableMap implements the traits.MutableMapper interface method, converting a mutable map
// an immutable map implementation.
func (m *mutableMap) ToImmutableMap() traits.Mapper {
return NewRefValMap(m.Adapter, m.mutableValues)
}
func newJSONStructAccessor(adapter Adapter, st map[string]*structpb.Value) mapAccessor {
return &jsonStructAccessor{
Adapter: adapter,
@@ -350,6 +393,15 @@ func (a *jsonStructAccessor) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *jsonStructAccessor) Fold(f traits.Folder) {
for k, v := range a.st {
if !f.FoldEntry(k, v) {
break
}
}
}
func newReflectMapAccessor(adapter Adapter, value reflect.Value) mapAccessor {
keyType := value.Type().Key()
return &reflectMapAccessor{
@@ -424,6 +476,16 @@ func (m *reflectMapAccessor) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (m *reflectMapAccessor) Fold(f traits.Folder) {
mapRange := m.refValue.MapRange()
for mapRange.Next() {
if !f.FoldEntry(mapRange.Key().Interface(), mapRange.Value().Interface()) {
break
}
}
}
func newRefValMapAccessor(mapVal map[ref.Val]ref.Val) mapAccessor {
return &refValMapAccessor{mapVal: mapVal}
}
@@ -477,6 +539,15 @@ func (a *refValMapAccessor) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *refValMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(k, v) {
break
}
}
}
func newStringMapAccessor(strMap map[string]string) mapAccessor {
return &stringMapAccessor{mapVal: strMap}
}
@@ -515,6 +586,15 @@ func (a *stringMapAccessor) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *stringMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(k, v) {
break
}
}
}
func newStringIfaceMapAccessor(adapter Adapter, mapVal map[string]any) mapAccessor {
return &stringIfaceMapAccessor{
Adapter: adapter,
@@ -557,6 +637,15 @@ func (a *stringIfaceMapAccessor) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (a *stringIfaceMapAccessor) Fold(f traits.Folder) {
for k, v := range a.mapVal {
if !f.FoldEntry(k, v) {
break
}
}
}
// protoMap is a specialized, separate implementation of the traits.Mapper interfaces tailored to
// accessing protoreflect.Map values.
type protoMap struct {
@@ -769,6 +858,13 @@ func (m *protoMap) Iterator() traits.Iterator {
}
}
// Fold calls the FoldEntry method for each (key, value) pair in the map.
func (m *protoMap) Fold(f traits.Folder) {
m.value.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
return f.FoldEntry(k.Interface(), v.Interface())
})
}
// Size returns the number of entries in the protoreflect.Map.
func (m *protoMap) Size() ref.Val {
return Int(m.value.Len())
@@ -852,3 +948,55 @@ func (it *stringKeyIterator) Next() ref.Val {
}
return nil
}
// ToFoldableMap will create a Foldable version of a map suitable for key-value pair iteration.
//
// For values which are already Foldable, this call is a no-op. For all other values, the fold
// is driven via the Iterator HasNext() and Next() calls as well as the map's Get() method
// which means that the folding will function, but take a performance hit.
func ToFoldableMap(m traits.Mapper) traits.Foldable {
if f, ok := m.(traits.Foldable); ok {
return f
}
return interopFoldableMap{Mapper: m}
}
type interopFoldableMap struct {
traits.Mapper
}
func (m interopFoldableMap) Fold(f traits.Folder) {
it := m.Iterator()
for it.HasNext() == True {
k := it.Next()
if !f.FoldEntry(k, m.Get(k)) {
break
}
}
}
// InsertMapKeyValue inserts a key, value pair into the target map if the target map does not
// already contain the given key.
//
// If the map is mutable, it is modified in-place per the MutableMapper contract.
// If the map is not mutable, a copy containing the new key, value pair is made.
func InsertMapKeyValue(m traits.Mapper, k, v ref.Val) ref.Val {
if mutable, ok := m.(traits.MutableMapper); ok {
return mutable.Insert(k, v)
}
// Otherwise perform the slow version of the insertion which makes a copy of the incoming map.
if _, found := m.Find(k); !found {
size := m.Size().(Int)
copy := make(map[ref.Val]ref.Val, size+1)
copy[k] = v
it := m.Iterator()
for it.HasNext() == True {
nextK := it.Next()
nextV := m.Get(nextK)
copy[nextK] = nextV
}
return DefaultTypeAdapter.NativeToValue(copy)
}
return NewErr("insert failed: key %v already exists", k)
}

View File

@@ -35,6 +35,8 @@ var (
// golang reflect type for Null values.
nullReflectType = reflect.TypeOf(NullValue)
protoIfaceType = reflect.TypeOf((*proto.Message)(nil)).Elem()
)
// ConvertToNative implements ref.Val.ConvertToNative.
@@ -61,8 +63,14 @@ func (n Null) ConvertToNative(typeDesc reflect.Type) (any, error) {
return structpb.NewNullValue(), nil
case boolWrapperType, byteWrapperType, doubleWrapperType, floatWrapperType,
int32WrapperType, int64WrapperType, stringWrapperType, uint32WrapperType,
uint64WrapperType:
uint64WrapperType, durationValueType, timestampValueType, protoIfaceType:
return nil, nil
case jsonListValueType, jsonStructType:
// skip handling
default:
if typeDesc.Implements(protoIfaceType) {
return nil, nil
}
}
case reflect.Interface:
nv := n.Value()

View File

@@ -427,22 +427,49 @@ func unwrap(desc description, msg proto.Message) (any, bool, error) {
return structpb.NullValue_NULL_VALUE, true, nil
}
case *wrapperspb.BoolValue:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
case *wrapperspb.BytesValue:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
case *wrapperspb.DoubleValue:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
case *wrapperspb.FloatValue:
if v == nil {
return nil, true, nil
}
return float64(v.GetValue()), true, nil
case *wrapperspb.Int32Value:
if v == nil {
return nil, true, nil
}
return int64(v.GetValue()), true, nil
case *wrapperspb.Int64Value:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
case *wrapperspb.StringValue:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
case *wrapperspb.UInt32Value:
if v == nil {
return nil, true, nil
}
return uint64(v.GetValue()), true, nil
case *wrapperspb.UInt64Value:
if v == nil {
return nil, true, nil
}
return v.GetValue(), true, nil
}
return msg, false, nil

View File

@@ -585,6 +585,14 @@ func nativeToValue(a Adapter, value any) (ref.Val, bool) {
refKind := refValue.Kind()
switch refKind {
case reflect.Array, reflect.Slice:
if refValue.Type().Elem() == reflect.TypeOf(byte(0)) {
if refValue.CanAddr() {
return Bytes(refValue.Bytes()), true
}
tmp := reflect.New(refValue.Type())
tmp.Elem().Set(refValue)
return Bytes(tmp.Elem().Bytes()), true
}
return NewDynamicList(a, v), true
case reflect.Map:
return NewDynamicMap(a, v), true

View File

@@ -34,3 +34,16 @@ type Iterator interface {
// Next returns the next element.
Next() ref.Val
}
// Foldable aggregate types support iteration over (key, value) or (index, value) pairs.
type Foldable interface {
// Fold invokes the Folder.FoldEntry for all entries in the type
Fold(Folder)
}
// Folder performs a fold on a given entry and indicates whether to continue folding.
type Folder interface {
// FoldEntry indicates the key, value pair associated with the entry.
// If the output is true, continue folding. Otherwise, terminate the fold.
FoldEntry(key, val any) bool
}

View File

@@ -27,6 +27,9 @@ type Lister interface {
}
// MutableLister interface which emits an immutable result after an intermediate computation.
//
// Note, this interface is intended only to be used within Comprehensions where the mutable
// value is not directly observable within the user-authored CEL expression.
type MutableLister interface {
Lister
ToImmutableList() Lister

View File

@@ -31,3 +31,18 @@ type Mapper interface {
// (Unknown|Err, false).
Find(key ref.Val) (ref.Val, bool)
}
// MutableMapper interface which emits an immutable result after an intermediate computation.
//
// Note, this interface is intended only to be used within Comprehensions where the mutable
// value is not directly observable within the user-authored CEL expression.
type MutableMapper interface {
Mapper
// Insert a key, value pair into the map, returning the map if the insert is successful
// and an error if key already exists in the mutable map.
Insert(k, v ref.Val) ref.Val
// ToImmutableMap converts a mutable map into an immutable map.
ToImmutableMap() Mapper
}

View File

@@ -59,6 +59,21 @@ const (
// SizerType types support the size() method.
SizerType
// SubtractorType type support '-' operations.
// SubtractorType types support '-' operations.
SubtractorType
// FoldableType types support comprehensions v2 macros which iterate over (key, value) pairs.
FoldableType
)
const (
// ListerType supports a set of traits necessary for list operations.
//
// The ListerType is syntactic sugar and not intended to be a perfect reflection of all List operators.
ListerType = AdderType | ContainerType | IndexerType | IterableType | SizerType
// MapperType supports a set of traits necessary for map operations.
//
// The MapperType is syntactic sugar and not intended to be a perfect reflection of all Map operators.
MapperType = ContainerType | IndexerType | IterableType | SizerType
)

View File

@@ -19,10 +19,13 @@ import (
"reflect"
"strings"
"google.golang.org/protobuf/proto"
chkdecls "github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
celpb "cel.dev/expr"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
@@ -666,85 +669,99 @@ func TypeToExprType(t *Type) (*exprpb.Type, error) {
// ExprTypeToType converts a protobuf CEL type representation to a CEL-native type representation.
func ExprTypeToType(t *exprpb.Type) (*Type, error) {
return AlphaProtoAsType(t)
}
// AlphaProtoAsType converts a CEL v1alpha1.Type protobuf type to a CEL-native type representation.
func AlphaProtoAsType(t *exprpb.Type) (*Type, error) {
canonical := &celpb.Type{}
if err := convertProto(t, canonical); err != nil {
return nil, err
}
return ProtoAsType(canonical)
}
// ProtoAsType converts a canonical CEL celpb.Type protobuf type to a CEL-native type representation.
func ProtoAsType(t *celpb.Type) (*Type, error) {
switch t.GetTypeKind().(type) {
case *exprpb.Type_Dyn:
case *celpb.Type_Dyn:
return DynType, nil
case *exprpb.Type_AbstractType_:
case *celpb.Type_AbstractType_:
paramTypes := make([]*Type, len(t.GetAbstractType().GetParameterTypes()))
for i, p := range t.GetAbstractType().GetParameterTypes() {
pt, err := ExprTypeToType(p)
pt, err := ProtoAsType(p)
if err != nil {
return nil, err
}
paramTypes[i] = pt
}
return NewOpaqueType(t.GetAbstractType().GetName(), paramTypes...), nil
case *exprpb.Type_ListType_:
et, err := ExprTypeToType(t.GetListType().GetElemType())
case *celpb.Type_ListType_:
et, err := ProtoAsType(t.GetListType().GetElemType())
if err != nil {
return nil, err
}
return NewListType(et), nil
case *exprpb.Type_MapType_:
kt, err := ExprTypeToType(t.GetMapType().GetKeyType())
case *celpb.Type_MapType_:
kt, err := ProtoAsType(t.GetMapType().GetKeyType())
if err != nil {
return nil, err
}
vt, err := ExprTypeToType(t.GetMapType().GetValueType())
vt, err := ProtoAsType(t.GetMapType().GetValueType())
if err != nil {
return nil, err
}
return NewMapType(kt, vt), nil
case *exprpb.Type_MessageType:
case *celpb.Type_MessageType:
return NewObjectType(t.GetMessageType()), nil
case *exprpb.Type_Null:
case *celpb.Type_Null:
return NullType, nil
case *exprpb.Type_Primitive:
case *celpb.Type_Primitive:
switch t.GetPrimitive() {
case exprpb.Type_BOOL:
case celpb.Type_BOOL:
return BoolType, nil
case exprpb.Type_BYTES:
case celpb.Type_BYTES:
return BytesType, nil
case exprpb.Type_DOUBLE:
case celpb.Type_DOUBLE:
return DoubleType, nil
case exprpb.Type_INT64:
case celpb.Type_INT64:
return IntType, nil
case exprpb.Type_STRING:
case celpb.Type_STRING:
return StringType, nil
case exprpb.Type_UINT64:
case celpb.Type_UINT64:
return UintType, nil
default:
return nil, fmt.Errorf("unsupported primitive type: %v", t)
}
case *exprpb.Type_TypeParam:
case *celpb.Type_TypeParam:
return NewTypeParamType(t.GetTypeParam()), nil
case *exprpb.Type_Type:
case *celpb.Type_Type:
if t.GetType().GetTypeKind() != nil {
p, err := ExprTypeToType(t.GetType())
p, err := ProtoAsType(t.GetType())
if err != nil {
return nil, err
}
return NewTypeTypeWithParam(p), nil
}
return TypeType, nil
case *exprpb.Type_WellKnown:
case *celpb.Type_WellKnown:
switch t.GetWellKnown() {
case exprpb.Type_ANY:
case celpb.Type_ANY:
return AnyType, nil
case exprpb.Type_DURATION:
case celpb.Type_DURATION:
return DurationType, nil
case exprpb.Type_TIMESTAMP:
case celpb.Type_TIMESTAMP:
return TimestampType, nil
default:
return nil, fmt.Errorf("unsupported well-known type: %v", t)
}
case *exprpb.Type_Wrapper:
t, err := ExprTypeToType(&exprpb.Type{TypeKind: &exprpb.Type_Primitive{Primitive: t.GetWrapper()}})
case *celpb.Type_Wrapper:
t, err := ProtoAsType(&celpb.Type{TypeKind: &celpb.Type_Primitive{Primitive: t.GetWrapper()}})
if err != nil {
return nil, err
}
return NewNullableType(t), nil
case *exprpb.Type_Error:
case *celpb.Type_Error:
return ErrorType, nil
default:
return nil, fmt.Errorf("unsupported type: %v", t)
@@ -776,6 +793,23 @@ func maybeForeignType(t ref.Type) *Type {
return NewObjectType(t.TypeName(), traitMask)
}
func convertProto(src, dst proto.Message) error {
pb, err := proto.Marshal(src)
if err != nil {
return err
}
err = proto.Unmarshal(pb, dst)
return err
}
func primitiveType(primitive celpb.Type_PrimitiveType) *celpb.Type {
return &celpb.Type{
TypeKind: &celpb.Type_Primitive{
Primitive: primitive,
},
}
}
var (
checkedWellKnowns = map[string]*Type{
// Wrapper types.
@@ -820,4 +854,11 @@ var (
}
structTypeTraitMask = traits.FieldTesterType | traits.IndexerType
boolType = primitiveType(celpb.Type_BOOL)
bytesType = primitiveType(celpb.Type_BYTES)
doubleType = primitiveType(celpb.Type_DOUBLE)
intType = primitiveType(celpb.Type_INT64)
stringType = primitiveType(celpb.Type_STRING)
uintType = primitiveType(celpb.Type_UINT64)
)

View File

@@ -24,6 +24,7 @@ go_library(
"//cel:go_default_library",
"//checker:go_default_library",
"//common/ast:go_default_library",
"//common/decls:go_default_library",
"//common/overloads:go_default_library",
"//common/operators:go_default_library",
"//common/types:go_default_library",
@@ -31,6 +32,7 @@ go_library(
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"//interpreter:go_default_library",
"//parser: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/structpb",
@@ -61,8 +63,8 @@ go_test(
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"//test:go_default_library",
"//test/proto2pb:go_default_library",
"//test/proto3pb:go_default_library",
"//test/proto2pb:go_default_library",
"//test/proto3pb:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",

View File

@@ -3,12 +3,12 @@
CEL extensions are a related set of constants, functions, macros, or other
features which may not be covered by the core CEL spec.
## Bindings
## Bindings
Returns a cel.EnvOption to configure support for local variable bindings
in expressions.
# Cel.Bind
### Cel.Bind
Binds a simple identifier to an initialization expression which may be used
in a subsequenct result expression. Bindings may also be nested within each
@@ -19,11 +19,11 @@ other.
Examples:
cel.bind(a, 'hello',
cel.bind(b, 'world', a + b + b + a)) // "helloworldworldhello"
cel.bind(b, 'world', a + b + b + a)) // "helloworldworldhello"
// Avoid a list allocation within the exists comprehension.
cel.bind(valid_values, [a, b, c],
[d, e, f].exists(elem, elem in valid_values))
[d, e, f].exists(elem, elem in valid_values))
Local bindings are not guaranteed to be evaluated before use.
@@ -100,7 +100,8 @@ argument. Simple numeric and list literals are supported as valid argument
types; however, other literals will be flagged as errors during macro
expansion. If the argument expression does not resolve to a numeric or
list(numeric) type during type-checking, or during runtime then an error
will be produced. If a list argument is empty, this too will produce an error.
will be produced. If a list argument is empty, this too will produce an
error.
math.least(<arg>, ...) -> <double|int|uint>
@@ -117,6 +118,244 @@ Examples:
math.least(a, b) // check-time error if a or b is non-numeric
math.least(dyn('string')) // runtime error
### Math.BitOr
Introduced at version: 1
Performs a bitwise-OR operation over two int or uint values.
math.bitOr(<int>, <int>) -> <int>
math.bitOr(<uint>, <uint>) -> <uint>
Examples:
math.bitOr(1u, 2u) // returns 3u
math.bitOr(-2, -4) // returns -2
### Math.BitAnd
Introduced at version: 1
Performs a bitwise-AND operation over two int or uint values.
math.bitAnd(<int>, <int>) -> <int>
math.bitAnd(<uint>, <uint>) -> <uint>
Examples:
math.bitAnd(3u, 2u) // return 2u
math.bitAnd(3, 5) // returns 3
math.bitAnd(-3, -5) // returns -7
### Math.BitXor
Introduced at version: 1
math.bitXor(<int>, <int>) -> <int>
math.bitXor(<uint>, <uint>) -> <uint>
Performs a bitwise-XOR operation over two int or uint values.
Examples:
math.bitXor(3u, 5u) // returns 6u
math.bitXor(1, 3) // returns 2
### Math.BitNot
Introduced at version: 1
Function which accepts a single int or uint and performs a bitwise-NOT
ones-complement of the given binary value.
math.bitNot(<int>) -> <int>
math.bitNot(<uint>) -> <uint>
Examples
math.bitNot(1) // returns -1
math.bitNot(-1) // return 0
math.bitNot(0u) // returns 18446744073709551615u
### Math.BitShiftLeft
Introduced at version: 1
Perform a left shift of bits on the first parameter, by the amount of bits
specified in the second parameter. The first parameter is either a uint or
an int. The second parameter must be an int.
When the second parameter is 64 or greater, 0 will be always be returned
since the number of bits shifted is greater than or equal to the total bit
length of the number being shifted. Negative valued bit shifts will result
in a runtime error.
math.bitShiftLeft(<int>, <int>) -> <int>
math.bitShiftLeft(<uint>, <int>) -> <uint>
Examples
math.bitShiftLeft(1, 2) // returns 4
math.bitShiftLeft(-1, 2) // returns -4
math.bitShiftLeft(1u, 2) // return 4u
math.bitShiftLeft(1u, 200) // returns 0u
### Math.BitShiftRight
Introduced at version: 1
Perform a right shift of bits on the first parameter, by the amount of bits
specified in the second parameter. The first parameter is either a uint or
an int. The second parameter must be an int.
When the second parameter is 64 or greater, 0 will always be returned since
the number of bits shifted is greater than or equal to the total bit length
of the number being shifted. Negative valued bit shifts will result in a
runtime error.
The sign bit extension will not be preserved for this operation: vacant bits
on the left are filled with 0.
math.bitShiftRight(<int>, <int>) -> <int>
math.bitShiftRight(<uint>, <int>) -> <uint>
Examples
math.bitShiftRight(1024, 2) // returns 256
math.bitShiftRight(1024u, 2) // returns 256u
math.bitShiftRight(1024u, 64) // returns 0u
### Math.Ceil
Introduced at version: 1
Compute the ceiling of a double value.
math.ceil(<double>) -> <double>
Examples:
math.ceil(1.2) // returns 2.0
math.ceil(-1.2) // returns -1.0
### Math.Floor
Introduced at version: 1
Compute the floor of a double value.
math.floor(<double>) -> <double>
Examples:
math.floor(1.2) // returns 1.0
math.floor(-1.2) // returns -2.0
### Math.Round
Introduced at version: 1
Rounds the double value to the nearest whole number with ties rounding away
from zero, e.g. 1.5 -> 2.0, -1.5 -> -2.0.
math.round(<double>) -> <double>
Examples:
math.round(1.2) // returns 1.0
math.round(1.5) // returns 2.0
math.round(-1.5) // returns -2.0
### Math.Trunc
Introduced at version: 1
Truncates the fractional portion of the double value.
math.trunc(<double>) -> <double>
Examples:
math.trunc(-1.3) // returns -1.0
math.trunc(1.3) // returns 1.0
### Math.Abs
Introduced at version: 1
Returns the absolute value of the numeric type provided as input. If the
value is NaN, the output is NaN. If the input is int64 min, the function
will result in an overflow error.
math.abs(<double>) -> <double>
math.abs(<int>) -> <int>
math.abs(<uint>) -> <uint>
Examples:
math.abs(-1) // returns 1
math.abs(1) // returns 1
math.abs(-9223372036854775808) // overlflow error
### Math.Sign
Introduced at version: 1
Returns the sign of the numeric type, either -1, 0, 1 as an int, double, or
uint depending on the overload. For floating point values, if NaN is
provided as input, the output is also NaN. The implementation does not
differentiate between positive and negative zero.
math.sign(<double>) -> <double>
math.sign(<int>) -> <int>
math.sign(<uint>) -> <uint>
Examples:
math.sign(-42) // returns -1
math.sign(0) // returns 0
math.sign(42) // returns 1
### Math.IsInf
Introduced at version: 1
Returns true if the input double value is -Inf or +Inf.
math.isInf(<double>) -> <bool>
Examples:
math.isInf(1.0/0.0) // returns true
math.isInf(1.2) // returns false
### Math.IsNaN
Introduced at version: 1
Returns true if the input double value is NaN, false otherwise.
math.isNaN(<double>) -> <bool>
Examples:
math.isNaN(0.0/0.0) // returns true
math.isNaN(1.2) // returns false
### Math.IsFinite
Introduced at version: 1
Returns true if the value is a finite number. Equivalent in behavior to:
!math.isNaN(double) && !math.isInf(double)
math.isFinite(<double>) -> <bool>
Examples:
math.isFinite(0.0/0.0) // returns false
math.isFinite(1.2) // returns true
## Protos
Protos configure extended macros and functions for proto manipulation.
@@ -154,6 +393,65 @@ Example:
Extended functions for list manipulation. As a general note, all indices are
zero-based.
### Distinct
**Introduced in version 2**
Returns the distinct elements of a list.
<list(T)>.distinct() -> <list(T)>
Examples:
[1, 2, 2, 3, 3, 3].distinct() // return [1, 2, 3]
["b", "b", "c", "a", "c"].distinct() // return ["b", "c", "a"]
[1, "b", 2, "b"].distinct() // return [1, "b", 2]
### Flatten
**Introduced in version 1**
Flattens a list recursively.
If an optional depth is provided, the list is flattened to a the specificied level.
A negative depth value will result in an error.
<list>.flatten(<list>) -> <list>
<list>.flatten(<list>, <int>) -> <list>
Examples:
[1,[2,3],[4]].flatten() // return [1, 2, 3, 4]
[1,[2,[3,4]]].flatten() // return [1, 2, [3, 4]]
[1,2,[],[],[3,4]].flatten() // return [1, 2, 3, 4]
[1,[2,[3,[4]]]].flatten(2) // return [1, 2, 3, [4]]
[1,[2,[3,[4]]]].flatten(-1) // error
### Range
**Introduced in version 2**
Returns a list of integers from 0 to n-1.
lists.range(<int>) -> <list(int)>
Examples:
lists.range(5) -> [0, 1, 2, 3, 4]
### Reverse
**Introduced in version 2**
Returns the elements of a list in reverse order.
<list(T)>.reverse() -> <list(T)>
Examples:
[5, 3, 1, 2].reverse() // return [2, 1, 3, 5]
### Slice
@@ -164,7 +462,43 @@ Returns a new sub-list using the indexes provided.
Examples:
[1,2,3,4].slice(1, 3) // return [2, 3]
[1,2,3,4].slice(2, 4) // return [3 ,4]
[1,2,3,4].slice(2, 4) // return [3, 4]
### Sort
**Introduced in version 2**
Sorts a list with comparable elements. If the element type is not comparable
or the element types are not the same, the function will produce an error.
<list(T)>.sort() -> <list(T)>
T in {int, uint, double, bool, duration, timestamp, string, bytes}
Examples:
[3, 2, 1].sort() // return [1, 2, 3]
["b", "c", "a"].sort() // return ["a", "b", "c"]
[1, "b"].sort() // error
[[1, 2, 3]].sort() // error
### SortBy
**Introduced in version 2**
Sorts a list by a key value, i.e., the order is determined by the result of
an expression applied to each element of the list.
<list(T)>.sortBy(<bindingName>, <keyExpr>) -> <list(T)>
keyExpr returns a value in {int, uint, double, bool, duration, timestamp, string, bytes}
Examples:
[
Player { name: "foo", score: 0 },
Player { name: "bar", score: -10 },
Player { name: "baz", score: 1000 },
].sortBy(e, e.score).map(e, e.name)
== ["bar", "foo", "baz"]
## Sets
@@ -259,7 +593,8 @@ Examples:
'hello mellow'.indexOf('jello') // returns -1
'hello mellow'.indexOf('', 2) // returns 2
'hello mellow'.indexOf('ello', 2) // returns 7
'hello mellow'.indexOf('ello', 20) // error
'hello mellow'.indexOf('ello', 20) // returns -1
'hello mellow'.indexOf('ello', -1) // error
### Join
@@ -273,10 +608,10 @@ elements in the resulting string.
Examples:
['hello', 'mellow'].join() // returns 'hellomellow'
['hello', 'mellow'].join(' ') // returns 'hello mellow'
[].join() // returns ''
[].join('/') // returns ''
['hello', 'mellow'].join() // returns 'hellomellow'
['hello', 'mellow'].join(' ') // returns 'hello mellow'
[].join() // returns ''
[].join('/') // returns ''
### LastIndexOf
@@ -297,6 +632,7 @@ Examples:
'hello mellow'.lastIndexOf('ello') // returns 7
'hello mellow'.lastIndexOf('jello') // returns -1
'hello mellow'.lastIndexOf('ello', 6) // returns 1
'hello mellow'.lastIndexOf('ello', 20) // returns -1
'hello mellow'.lastIndexOf('ello', -1) // error
### LowerAscii
@@ -427,4 +763,137 @@ It can be located in Version 3 of strings.
Examples:
'gums'.reverse() // returns 'smug'
'John Smith'.reverse() // returns 'htimS nhoJ'
'John Smith'.reverse() // returns 'htimS nhoJ'
## TwoVarComprehensions
TwoVarComprehensions introduces support for two-variable comprehensions.
The two-variable form of comprehensions looks similar to the one-variable
counterparts. Where possible, the same macro names were used and additional
macro signatures added. The notable distinction for two-variable comprehensions
is the introduction of `transformList`, `transformMap`, and `transformMapEntry`
support for list and map types rather than the more traditional `map` and
`filter` macros.
### All
Comprehension which tests whether all elements in the list or map satisfy a
given predicate. The `all` macro evaluates in a manner consistent with logical
AND and will short-circuit when encountering a `false` value.
<list>.all(indexVar, valueVar, <predicate>) -> bool
<map>.all(keyVar, valueVar, <predicate>) -> bool
Examples:
[1, 2, 3].all(i, j, i < j) // returns true
{'hello': 'world', 'taco': 'taco'}.all(k, v, k != v) // returns false
// Combines two-variable comprehension with single variable
{'h': ['hello', 'hi'], 'j': ['joke', 'jog']}
.all(k, vals, vals.all(v, v.startsWith(k))) // returns true
### Exists
Comprehension which tests whether any element in a list or map exists which
satisfies a given predicate. The `exists` macro evaluates in a manner consistent
with logical OR and will short-circuit when encountering a `true` value.
<list>.exists(indexVar, valueVar, <predicate>) -> bool
<map>.exists(keyVar, valueVar, <predicate>) -> bool
Examples:
{'greeting': 'hello', 'farewell': 'goodbye'}
.exists(k, v, k.startsWith('good') || v.endsWith('bye')) // returns true
[1, 2, 4, 8, 16].exists(i, v, v == 1024 && i == 10) // returns false
### ExistsOne
Comprehension which tests whether exactly one element in a list or map exists
which satisfies a given predicate expression. This comprehension does not
short-circuit in keeping with the one-variable exists one macro semantics.
<list>.existsOne(indexVar, valueVar, <predicate>)
<map>.existsOne(keyVar, valueVar, <predicate>)
This macro may also be used with the `exists_one` function name, for
compatibility with the one-variable macro of the same name.
Examples:
[1, 2, 1, 3, 1, 4].existsOne(i, v, i == 1 || v == 1) // returns false
[1, 1, 2, 2, 3, 3].existsOne(i, v, i == 2 && v == 2) // returns true
{'i': 0, 'j': 1, 'k': 2}.existsOne(i, v, i == 'l' || v == 1) // returns true
### TransformList
Comprehension which converts a map or a list into a list value. The output
expression of the comprehension determines the contents of the output list.
Elements in the list may optionally be filtered according to a predicate
expression, where elements that satisfy the predicate are transformed.
<list>.transformList(indexVar, valueVar, <transform>)
<list>.transformList(indexVar, valueVar, <filter>, <transform>)
<map>.transformList(keyVar, valueVar, <transform>)
<map>.transformList(keyVar, valueVar, <filter>, <transform>)
Examples:
[1, 2, 3].transformList(indexVar, valueVar,
(indexVar * valueVar) + valueVar) // returns [1, 4, 9]
[1, 2, 3].transformList(indexVar, valueVar, indexVar % 2 == 0
(indexVar * valueVar) + valueVar) // returns [1, 9]
{'greeting': 'hello', 'farewell': 'goodbye'}
.transformList(k, _, k) // returns ['greeting', 'farewell']
{'greeting': 'hello', 'farewell': 'goodbye'}
.transformList(_, v, v) // returns ['hello', 'goodbye']
### TransformMap
Comprehension which converts a map or a list into a map value. The output
expression of the comprehension determines the value of the output map entry;
however, the key remains fixed. Elements in the map may optionally be filtered
according to a predicate expression, where elements that satisfy the predicate
are transformed.
<list>.transformMap(indexVar, valueVar, <transform>)
<list>.transformMap(indexVar, valueVar, <filter>, <transform>)
<map>.transformMap(keyVar, valueVar, <transform>)
<map>.transformMap(keyVar, valueVar, <filter>, <transform>)
Examples:
[1, 2, 3].transformMap(indexVar, valueVar,
(indexVar * valueVar) + valueVar) // returns {0: 1, 1: 4, 2: 9}
[1, 2, 3].transformMap(indexVar, valueVar, indexVar % 2 == 0
(indexVar * valueVar) + valueVar) // returns {0: 1, 2: 9}
{'greeting': 'hello'}.transformMap(k, v, v + '!') // returns {'greeting': 'hello!'}
### TransformMapEntry
Comprehension which converts a map or a list into a map value; however, this
transform expects the entry expression be a map literal. If the transform
produces an entry which duplicates a key in the target map, the comprehension
will error. Note, that key equality is determined using CEL equality which
asserts that numeric values which are equal, even if they don't have the same
type will cause a key collision.
Elements in the map may optionally be filtered according to a predicate
expression, where elements that satisfy the predicate are transformed.
<list>.transformMap(indexVar, valueVar, <transform>)
<list>.transformMap(indexVar, valueVar, <filter>, <transform>)
<map>.transformMap(keyVar, valueVar, <transform>)
<map>.transformMap(keyVar, valueVar, <filter>, <transform>)
Examples:
// returns {'hello': 'greeting'}
{'greeting': 'hello'}.transformMapEntry(keyVar, valueVar, {valueVar: keyVar})
// reverse lookup, require all values in list be unique
[1, 2, 3].transformMapEntry(indexVar, valueVar, {valueVar: indexVar})
{'greeting': 'aloha', 'farewell': 'aloha'}
.transformMapEntry(keyVar, valueVar, {valueVar: keyVar}) // error, duplicate key

View File

@@ -15,9 +15,19 @@
package ext
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
"sync"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/ast"
"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"
)
// Bindings returns a cel.EnvOption to configure support for local variable
@@ -41,35 +51,120 @@ import (
// [d, e, f].exists(elem, elem in valid_values))
//
// Local bindings are not guaranteed to be evaluated before use.
func Bindings() cel.EnvOption {
return cel.Lib(celBindings{})
func Bindings(options ...BindingsOption) cel.EnvOption {
b := &celBindings{version: math.MaxUint32}
for _, o := range options {
b = o(b)
}
return cel.Lib(b)
}
const (
celNamespace = "cel"
bindMacro = "bind"
blockFunc = "@block"
unusedIterVar = "#unused"
)
type celBindings struct{}
// BindingsOption declares a functional operator for configuring the Bindings library behavior.
type BindingsOption func(*celBindings) *celBindings
func (celBindings) LibraryName() string {
// BindingsVersion sets the version of the bindings library to an explicit version.
func BindingsVersion(version uint32) BindingsOption {
return func(lib *celBindings) *celBindings {
lib.version = version
return lib
}
}
type celBindings struct {
version uint32
}
func (*celBindings) LibraryName() string {
return "cel.lib.ext.cel.bindings"
}
func (celBindings) CompileOptions() []cel.EnvOption {
return []cel.EnvOption{
func (lib *celBindings) CompileOptions() []cel.EnvOption {
opts := []cel.EnvOption{
cel.Macros(
// cel.bind(var, <init>, <expr>)
cel.ReceiverMacro(bindMacro, 3, celBind),
),
}
if lib.version >= 1 {
// The cel.@block signature takes a list of subexpressions and a typed expression which is
// used as the output type.
paramType := cel.TypeParamType("T")
opts = append(opts,
cel.Function("cel.@block",
cel.Overload("cel_block_list",
[]*cel.Type{cel.ListType(cel.DynType), paramType}, paramType)),
)
opts = append(opts, cel.ASTValidators(blockValidationExemption{}))
}
return opts
}
func (celBindings) ProgramOptions() []cel.ProgramOption {
func (lib *celBindings) ProgramOptions() []cel.ProgramOption {
if lib.version >= 1 {
celBlockPlan := func(i interpreter.Interpretable) (interpreter.Interpretable, error) {
call, ok := i.(interpreter.InterpretableCall)
if !ok {
return i, nil
}
switch call.Function() {
case "cel.@block":
args := call.Args()
if len(args) != 2 {
return nil, fmt.Errorf("cel.@block expects two arguments, but got %d", len(args))
}
expr := args[1]
// Non-empty block
if block, ok := args[0].(interpreter.InterpretableConstructor); ok {
slotExprs := block.InitVals()
return newDynamicBlock(slotExprs, expr), nil
}
// Constant valued block which can happen during runtime optimization.
if cons, ok := args[0].(interpreter.InterpretableConst); ok {
if cons.Value().Type() == types.ListType {
l := cons.Value().(traits.Lister)
if l.Size().Equal(types.IntZero) == types.True {
return args[1], nil
}
return newConstantBlock(l, expr), nil
}
}
return nil, errors.New("cel.@block expects a list constructor as the first argument")
default:
return i, nil
}
}
return []cel.ProgramOption{cel.CustomDecorator(celBlockPlan)}
}
return []cel.ProgramOption{}
}
type blockValidationExemption struct{}
// Name returns the name of the validator.
func (blockValidationExemption) Name() string {
return "cel.lib.ext.validate.functions.cel.block"
}
// Configure implements the ASTValidatorConfigurer interface and augments the list of functions to skip
// during homogeneous aggregate literal type-checks.
func (blockValidationExemption) Configure(config cel.MutableValidatorConfig) error {
functions := config.GetOrDefault(cel.HomogeneousAggregateLiteralExemptFunctions, []string{}).([]string)
functions = append(functions, "cel.@block")
return config.Set(cel.HomogeneousAggregateLiteralExemptFunctions, functions)
}
// Validate is a no-op as the intent is to simply disable strong type-checks for list literals during
// when they occur within cel.@block calls as the arg types have already been validated.
func (blockValidationExemption) Validate(env *cel.Env, _ cel.ValidatorConfig, a *ast.AST, iss *cel.Issues) {
}
func celBind(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
if !macroTargetMatchesNamespace(celNamespace, target) {
return nil, nil
@@ -94,3 +189,148 @@ func celBind(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Ex
resultExpr,
), nil
}
func newDynamicBlock(slotExprs []interpreter.Interpretable, expr interpreter.Interpretable) interpreter.Interpretable {
bs := &dynamicBlock{
slotExprs: slotExprs,
expr: expr,
}
bs.slotActivationPool = &sync.Pool{
New: func() any {
slotCount := len(slotExprs)
sa := &dynamicSlotActivation{
slotExprs: slotExprs,
slotCount: slotCount,
slotVals: make([]*slotVal, slotCount),
}
for i := 0; i < slotCount; i++ {
sa.slotVals[i] = &slotVal{}
}
return sa
},
}
return bs
}
type dynamicBlock struct {
slotExprs []interpreter.Interpretable
expr interpreter.Interpretable
slotActivationPool *sync.Pool
}
// ID implements the Interpretable interface method.
func (b *dynamicBlock) ID() int64 {
return b.expr.ID()
}
// Eval implements the Interpretable interface method.
func (b *dynamicBlock) Eval(activation interpreter.Activation) ref.Val {
sa := b.slotActivationPool.Get().(*dynamicSlotActivation)
sa.Activation = activation
defer b.clearSlots(sa)
return b.expr.Eval(sa)
}
func (b *dynamicBlock) clearSlots(sa *dynamicSlotActivation) {
sa.reset()
b.slotActivationPool.Put(sa)
}
type slotVal struct {
value *ref.Val
visited bool
}
type dynamicSlotActivation struct {
interpreter.Activation
slotExprs []interpreter.Interpretable
slotCount int
slotVals []*slotVal
}
// ResolveName implements the Activation interface method but handles variables prefixed with `@index`
// as special variables which exist within the slot-based memory of the cel.@block() where each slot
// refers to an expression which must be computed only once.
func (sa *dynamicSlotActivation) ResolveName(name string) (any, bool) {
if idx, found := matchSlot(name, sa.slotCount); found {
v := sa.slotVals[idx]
if v.visited {
// Return not found if the index expression refers to itself
if v.value == nil {
return nil, false
}
return *v.value, true
}
v.visited = true
val := sa.slotExprs[idx].Eval(sa)
v.value = &val
return val, true
}
return sa.Activation.ResolveName(name)
}
func (sa *dynamicSlotActivation) reset() {
sa.Activation = nil
for _, sv := range sa.slotVals {
sv.visited = false
sv.value = nil
}
}
func newConstantBlock(slots traits.Lister, expr interpreter.Interpretable) interpreter.Interpretable {
count := slots.Size().(types.Int)
return &constantBlock{slots: slots, slotCount: int(count), expr: expr}
}
type constantBlock struct {
slots traits.Lister
slotCount int
expr interpreter.Interpretable
}
// ID implements the interpreter.Interpretable interface method.
func (b *constantBlock) ID() int64 {
return b.expr.ID()
}
// Eval implements the interpreter.Interpretable interface method, and will proxy @index prefixed variable
// lookups into a set of constant slots determined from the plan step.
func (b *constantBlock) Eval(activation interpreter.Activation) ref.Val {
vars := constantSlotActivation{Activation: activation, slots: b.slots, slotCount: b.slotCount}
return b.expr.Eval(vars)
}
type constantSlotActivation struct {
interpreter.Activation
slots traits.Lister
slotCount int
}
// ResolveName implements Activation interface method and proxies @index prefixed lookups into the slot
// activation associated with the block scope.
func (sa constantSlotActivation) ResolveName(name string) (any, bool) {
if idx, found := matchSlot(name, sa.slotCount); found {
return sa.slots.Get(types.Int(idx)), true
}
return sa.Activation.ResolveName(name)
}
func matchSlot(name string, slotCount int) (int, bool) {
if idx, found := strings.CutPrefix(name, indexPrefix); found {
idx, err := strconv.Atoi(idx)
// Return not found if the index is not numeric
if err != nil {
return -1, false
}
// Return not found if the index is not a valid slot
if idx < 0 || idx >= slotCount {
return -1, false
}
return idx, true
}
return -1, false
}
var (
indexPrefix = "@index"
)

410
vendor/github.com/google/cel-go/ext/comprehensions.go generated vendored Normal file
View File

@@ -0,0 +1,410 @@
// Copyright 2024 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 ext
import (
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/ast"
"github.com/google/cel-go/common/operators"
"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/parser"
)
const (
mapInsert = "cel.@mapInsert"
mapInsertOverloadMap = "@mapInsert_map_map"
mapInsertOverloadKeyValue = "@mapInsert_map_key_value"
)
// TwoVarComprehensions introduces support for two-variable comprehensions.
//
// The two-variable form of comprehensions looks similar to the one-variable counterparts.
// Where possible, the same macro names were used and additional macro signatures added.
// The notable distinction for two-variable comprehensions is the introduction of
// `transformList`, `transformMap`, and `transformMapEntry` support for list and map types
// rather than the more traditional `map` and `filter` macros.
//
// # All
//
// Comprehension which tests whether all elements in the list or map satisfy a given
// predicate. The `all` macro evaluates in a manner consistent with logical AND and will
// short-circuit when encountering a `false` value.
//
// <list>.all(indexVar, valueVar, <predicate>) -> bool
// <map>.all(keyVar, valueVar, <predicate>) -> bool
//
// Examples:
//
// [1, 2, 3].all(i, j, i < j) // returns true
// {'hello': 'world', 'taco': 'taco'}.all(k, v, k != v) // returns false
//
// // Combines two-variable comprehension with single variable
// {'h': ['hello', 'hi'], 'j': ['joke', 'jog']}
// .all(k, vals, vals.all(v, v.startsWith(k))) // returns true
//
// # Exists
//
// Comprehension which tests whether any element in a list or map exists which satisfies
// a given predicate. The `exists` macro evaluates in a manner consistent with logical OR
// and will short-circuit when encountering a `true` value.
//
// <list>.exists(indexVar, valueVar, <predicate>) -> bool
// <map>.exists(keyVar, valueVar, <predicate>) -> bool
//
// Examples:
//
// {'greeting': 'hello', 'farewell': 'goodbye'}
// .exists(k, v, k.startsWith('good') || v.endsWith('bye')) // returns true
// [1, 2, 4, 8, 16].exists(i, v, v == 1024 && i == 10) // returns false
//
// # ExistsOne
//
// Comprehension which tests whether exactly one element in a list or map exists which
// satisfies a given predicate expression. This comprehension does not short-circuit in
// keeping with the one-variable exists one macro semantics.
//
// <list>.existsOne(indexVar, valueVar, <predicate>)
// <map>.existsOne(keyVar, valueVar, <predicate>)
//
// This macro may also be used with the `exists_one` function name, for compatibility
// with the one-variable macro of the same name.
//
// Examples:
//
// [1, 2, 1, 3, 1, 4].existsOne(i, v, i == 1 || v == 1) // returns false
// [1, 1, 2, 2, 3, 3].existsOne(i, v, i == 2 && v == 2) // returns true
// {'i': 0, 'j': 1, 'k': 2}.existsOne(i, v, i == 'l' || v == 1) // returns true
//
// # TransformList
//
// Comprehension which converts a map or a list into a list value. The output expression
// of the comprehension determines the contents of the output list. Elements in the list
// may optionally be filtered according to a predicate expression, where elements that
// satisfy the predicate are transformed.
//
// <list>.transformList(indexVar, valueVar, <transform>)
// <list>.transformList(indexVar, valueVar, <filter>, <transform>)
// <map>.transformList(keyVar, valueVar, <transform>)
// <map>.transformList(keyVar, valueVar, <filter>, <transform>)
//
// Examples:
//
// [1, 2, 3].transformList(indexVar, valueVar,
// (indexVar * valueVar) + valueVar) // returns [1, 4, 9]
// [1, 2, 3].transformList(indexVar, valueVar, indexVar % 2 == 0
// (indexVar * valueVar) + valueVar) // returns [1, 9]
// {'greeting': 'hello', 'farewell': 'goodbye'}
// .transformList(k, _, k) // returns ['greeting', 'farewell']
// {'greeting': 'hello', 'farewell': 'goodbye'}
// .transformList(_, v, v) // returns ['hello', 'goodbye']
//
// # TransformMap
//
// Comprehension which converts a map or a list into a map value. The output expression
// of the comprehension determines the value of the output map entry; however, the key
// remains fixed. Elements in the map may optionally be filtered according to a predicate
// expression, where elements that satisfy the predicate are transformed.
//
// <list>.transformMap(indexVar, valueVar, <transform>)
// <list>.transformMap(indexVar, valueVar, <filter>, <transform>)
// <map>.transformMap(keyVar, valueVar, <transform>)
// <map>.transformMap(keyVar, valueVar, <filter>, <transform>)
//
// Examples:
//
// [1, 2, 3].transformMap(indexVar, valueVar,
// (indexVar * valueVar) + valueVar) // returns {0: 1, 1: 4, 2: 9}
// [1, 2, 3].transformMap(indexVar, valueVar, indexVar % 2 == 0
// (indexVar * valueVar) + valueVar) // returns {0: 1, 2: 9}
// {'greeting': 'hello'}.transformMap(k, v, v + '!') // returns {'greeting': 'hello!'}
//
// # TransformMapEntry
//
// Comprehension which converts a map or a list into a map value; however, this transform
// expects the entry expression be a map literal. If the tranform produces an entry which
// duplicates a key in the target map, the comprehension will error. Note, that key
// equality is determined using CEL equality which asserts that numeric values which are
// equal, even if they don't have the same type will cause a key collision.
//
// Elements in the map may optionally be filtered according to a predicate expression, where
// elements that satisfy the predicate are transformed.
//
// <list>.transformMap(indexVar, valueVar, <transform>)
// <list>.transformMap(indexVar, valueVar, <filter>, <transform>)
// <map>.transformMap(keyVar, valueVar, <transform>)
// <map>.transformMap(keyVar, valueVar, <filter>, <transform>)
//
// Examples:
//
// // returns {'hello': 'greeting'}
// {'greeting': 'hello'}.transformMapEntry(keyVar, valueVar, {valueVar: keyVar})
// // reverse lookup, require all values in list be unique
// [1, 2, 3].transformMapEntry(indexVar, valueVar, {valueVar: indexVar})
//
// {'greeting': 'aloha', 'farewell': 'aloha'}
// .transformMapEntry(keyVar, valueVar, {valueVar: keyVar}) // error, duplicate key
func TwoVarComprehensions() cel.EnvOption {
return cel.Lib(compreV2Lib{})
}
type compreV2Lib struct{}
// LibraryName implements that SingletonLibrary interface method.
func (compreV2Lib) LibraryName() string {
return "cel.lib.ext.comprev2"
}
// CompileOptions implements the cel.Library interface method.
func (compreV2Lib) CompileOptions() []cel.EnvOption {
kType := cel.TypeParamType("K")
vType := cel.TypeParamType("V")
mapKVType := cel.MapType(kType, vType)
opts := []cel.EnvOption{
cel.Macros(
cel.ReceiverMacro("all", 3, quantifierAll),
cel.ReceiverMacro("exists", 3, quantifierExists),
cel.ReceiverMacro("existsOne", 3, quantifierExistsOne),
cel.ReceiverMacro("exists_one", 3, quantifierExistsOne),
cel.ReceiverMacro("transformList", 3, transformList),
cel.ReceiverMacro("transformList", 4, transformList),
cel.ReceiverMacro("transformMap", 3, transformMap),
cel.ReceiverMacro("transformMap", 4, transformMap),
cel.ReceiverMacro("transformMapEntry", 3, transformMapEntry),
cel.ReceiverMacro("transformMapEntry", 4, transformMapEntry),
),
cel.Function(mapInsert,
cel.Overload(mapInsertOverloadKeyValue, []*cel.Type{mapKVType, kType, vType}, mapKVType,
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
m := args[0].(traits.Mapper)
k := args[1]
v := args[2]
return types.InsertMapKeyValue(m, k, v)
})),
cel.Overload(mapInsertOverloadMap, []*cel.Type{mapKVType, mapKVType}, mapKVType,
cel.BinaryBinding(func(targetMap, updateMap ref.Val) ref.Val {
tm := targetMap.(traits.Mapper)
um := updateMap.(traits.Mapper)
umIt := um.Iterator()
for umIt.HasNext() == types.True {
k := umIt.Next()
updateOrErr := types.InsertMapKeyValue(tm, k, um.Get(k))
if types.IsError(updateOrErr) {
return updateOrErr
}
tm = updateOrErr.(traits.Mapper)
}
return tm
})),
),
}
return opts
}
// ProgramOptions implements the cel.Library interface method
func (compreV2Lib) ProgramOptions() []cel.ProgramOption {
return []cel.ProgramOption{}
}
func quantifierAll(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewLiteral(types.True),
/*condition=*/ mef.NewCall(operators.NotStrictlyFalse, mef.NewAccuIdent()),
/*step=*/ mef.NewCall(operators.LogicalAnd, mef.NewAccuIdent(), args[2]),
/*result=*/ mef.NewAccuIdent(),
), nil
}
func quantifierExists(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewLiteral(types.False),
/*condition=*/ mef.NewCall(operators.NotStrictlyFalse, mef.NewCall(operators.LogicalNot, mef.NewAccuIdent())),
/*step=*/ mef.NewCall(operators.LogicalOr, mef.NewAccuIdent(), args[2]),
/*result=*/ mef.NewAccuIdent(),
), nil
}
func quantifierExistsOne(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewLiteral(types.Int(0)),
/*condition=*/ mef.NewLiteral(types.True),
/*step=*/ mef.NewCall(operators.Conditional, args[2],
mef.NewCall(operators.Add, mef.NewAccuIdent(), mef.NewLiteral(types.Int(1))),
mef.NewAccuIdent()),
/*result=*/ mef.NewCall(operators.Equals, mef.NewAccuIdent(), mef.NewLiteral(types.Int(1))),
), nil
}
func transformList(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
var transform ast.Expr
var filter ast.Expr
if len(args) == 4 {
filter = args[2]
transform = args[3]
} else {
filter = nil
transform = args[2]
}
// __result__ = __result__ + [transform]
step := mef.NewCall(operators.Add, mef.NewAccuIdent(), mef.NewList(transform))
if filter != nil {
// __result__ = (filter) ? __result__ + [transform] : __result__
step = mef.NewCall(operators.Conditional, filter, step, mef.NewAccuIdent())
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewList(),
/*condition=*/ mef.NewLiteral(types.True),
step,
/*result=*/ mef.NewAccuIdent(),
), nil
}
func transformMap(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
var transform ast.Expr
var filter ast.Expr
if len(args) == 4 {
filter = args[2]
transform = args[3]
} else {
filter = nil
transform = args[2]
}
// __result__ = cel.@mapInsert(__result__, iterVar1, transform)
step := mef.NewCall(mapInsert, mef.NewAccuIdent(), mef.NewIdent(iterVar1), transform)
if filter != nil {
// __result__ = (filter) ? cel.@mapInsert(__result__, iterVar1, transform) : __result__
step = mef.NewCall(operators.Conditional, filter, step, mef.NewAccuIdent())
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewMap(),
/*condition=*/ mef.NewLiteral(types.True),
step,
/*result=*/ mef.NewAccuIdent(),
), nil
}
func transformMapEntry(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
iterVar1, iterVar2, err := extractIterVars(mef, args[0], args[1])
if err != nil {
return nil, err
}
var transform ast.Expr
var filter ast.Expr
if len(args) == 4 {
filter = args[2]
transform = args[3]
} else {
filter = nil
transform = args[2]
}
// __result__ = cel.@mapInsert(__result__, transform)
step := mef.NewCall(mapInsert, mef.NewAccuIdent(), transform)
if filter != nil {
// __result__ = (filter) ? cel.@mapInsert(__result__, transform) : __result__
step = mef.NewCall(operators.Conditional, filter, step, mef.NewAccuIdent())
}
return mef.NewComprehensionTwoVar(
target,
iterVar1,
iterVar2,
parser.AccumulatorName,
/*accuInit=*/ mef.NewMap(),
/*condition=*/ mef.NewLiteral(types.True),
step,
/*result=*/ mef.NewAccuIdent(),
), nil
}
func extractIterVars(mef cel.MacroExprFactory, arg0, arg1 ast.Expr) (string, string, *cel.Error) {
iterVar1, err := extractIterVar(mef, arg0)
if err != nil {
return "", "", err
}
iterVar2, err := extractIterVar(mef, arg1)
if err != nil {
return "", "", err
}
if iterVar1 == iterVar2 {
return "", "", mef.NewError(arg1.ID(), fmt.Sprintf("duplicate variable name: %s", iterVar1))
}
if iterVar1 == parser.AccumulatorName {
return "", "", mef.NewError(arg0.ID(), "iteration variable overwrites accumulator variable")
}
if iterVar2 == parser.AccumulatorName {
return "", "", mef.NewError(arg1.ID(), "iteration variable overwrites accumulator variable")
}
return iterVar1, iterVar2, nil
}
func extractIterVar(mef cel.MacroExprFactory, target ast.Expr) (string, *cel.Error) {
iterVar, found := extractIdent(target)
if !found {
return "", mef.NewError(target.ID(), "argument must be a simple name")
}
return iterVar, nil
}

View File

@@ -36,7 +36,7 @@ import (
// Examples:
//
// base64.decode('aGVsbG8=') // return b'hello'
// base64.decode('aGVsbG8') // error
// base64.decode('aGVsbG8') // return b'hello'
//
// # Base64.Encode
//
@@ -79,7 +79,14 @@ func (encoderLib) ProgramOptions() []cel.ProgramOption {
}
func base64DecodeString(str string) ([]byte, error) {
return base64.StdEncoding.DecodeString(str)
b, err := base64.StdEncoding.DecodeString(str)
if err == nil {
return b, nil
}
if _, tryAltEncoding := err.(base64.CorruptInputError); tryAltEncoding {
return base64.RawStdEncoding.DecodeString(str)
}
return nil, err
}
func base64EncodeBytes(bytes []byte) (string, error) {

View File

@@ -484,7 +484,7 @@ func matchConstantFormatStringWithListLiteralArgs(a *ast.AST) ast.ExprMatcher {
}
}
formatString := call.Target()
if formatString.Kind() != ast.LiteralKind && formatString.AsLiteral().Type() != cel.StringType {
if formatString.Kind() != ast.LiteralKind || formatString.AsLiteral().Type() != cel.StringType {
return false
}
args := call.Args()

View File

@@ -50,14 +50,18 @@ func listStringOrError(strs []string, err error) ref.Val {
return types.DefaultTypeAdapter.NativeToValue(strs)
}
func macroTargetMatchesNamespace(ns string, target ast.Expr) bool {
func extractIdent(target ast.Expr) (string, bool) {
switch target.Kind() {
case ast.IdentKind:
if target.AsIdent() != ns {
return false
}
return true
return target.AsIdent(), true
default:
return false
return "", false
}
}
func macroTargetMatchesNamespace(ns string, target ast.Expr) bool {
if id, found := extractIdent(target); found {
return id == ns
}
return false
}

View File

@@ -16,15 +16,70 @@ package ext
import (
"fmt"
"math"
"sort"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/ast"
"github.com/google/cel-go/common/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/parser"
)
var comparableTypes = []*cel.Type{
cel.IntType,
cel.UintType,
cel.DoubleType,
cel.BoolType,
cel.DurationType,
cel.TimestampType,
cel.StringType,
cel.BytesType,
}
// Lists returns a cel.EnvOption to configure extended functions for list manipulation.
// As a general note, all indices are zero-based.
//
// # Distinct
//
// Introduced in version: 2
//
// Returns the distinct elements of a list.
//
// <list(T)>.distinct() -> <list(T)>
//
// Examples:
//
// [1, 2, 2, 3, 3, 3].distinct() // return [1, 2, 3]
// ["b", "b", "c", "a", "c"].distinct() // return ["b", "c", "a"]
// [1, "b", 2, "b"].distinct() // return [1, "b", 2]
//
// # Range
//
// Introduced in version: 2
//
// Returns a list of integers from 0 to n-1.
//
// lists.range(<int>) -> <list(int)>
//
// Examples:
//
// lists.range(5) -> [0, 1, 2, 3, 4]
//
// # Reverse
//
// Introduced in version: 2
//
// Returns the elements of a list in reverse order.
//
// <list(T)>.reverse() -> <list(T)>
//
// Examples:
//
// [5, 3, 1, 2].reverse() // return [2, 1, 3, 5]
//
// # Slice
//
// Returns a new sub-list using the indexes provided.
@@ -35,21 +90,105 @@ import (
//
// [1,2,3,4].slice(1, 3) // return [2, 3]
// [1,2,3,4].slice(2, 4) // return [3 ,4]
func Lists() cel.EnvOption {
return cel.Lib(listsLib{})
//
// # Flatten
//
// Flattens a list recursively.
// If an optional depth is provided, the list is flattened to a the specificied level.
// A negative depth value will result in an error.
//
// <list>.flatten(<list>) -> <list>
// <list>.flatten(<list>, <int>) -> <list>
//
// Examples:
//
// [1,[2,3],[4]].flatten() // return [1, 2, 3, 4]
// [1,[2,[3,4]]].flatten() // return [1, 2, [3, 4]]
// [1,2,[],[],[3,4]].flatten() // return [1, 2, 3, 4]
// [1,[2,[3,[4]]]].flatten(2) // return [1, 2, 3, [4]]
// [1,[2,[3,[4]]]].flatten(-1) // error
//
// # Sort
//
// Introduced in version: 2
//
// Sorts a list with comparable elements. If the element type is not comparable
// or the element types are not the same, the function will produce an error.
//
// <list(T)>.sort() -> <list(T)>
// T in {int, uint, double, bool, duration, timestamp, string, bytes}
//
// Examples:
//
// [3, 2, 1].sort() // return [1, 2, 3]
// ["b", "c", "a"].sort() // return ["a", "b", "c"]
// [1, "b"].sort() // error
// [[1, 2, 3]].sort() // error
//
// # SortBy
//
// Sorts a list by a key value, i.e., the order is determined by the result of
// an expression applied to each element of the list.
// The output of the key expression must be a comparable type, otherwise the
// function will return an error.
//
// <list(T)>.sortBy(<bindingName>, <keyExpr>) -> <list(T)>
// keyExpr returns a value in {int, uint, double, bool, duration, timestamp, string, bytes}
// Examples:
//
// [
// Player { name: "foo", score: 0 },
// Player { name: "bar", score: -10 },
// Player { name: "baz", score: 1000 },
// ].sortBy(e, e.score).map(e, e.name)
// == ["bar", "foo", "baz"]
func Lists(options ...ListsOption) cel.EnvOption {
l := &listsLib{
version: math.MaxUint32,
}
for _, o := range options {
l = o(l)
}
return cel.Lib(l)
}
type listsLib struct{}
type listsLib struct {
version uint32
}
// LibraryName implements the SingletonLibrary interface method.
func (listsLib) LibraryName() string {
return "cel.lib.ext.lists"
}
// ListsOption is a functional interface for configuring the strings library.
type ListsOption func(*listsLib) *listsLib
// ListsVersion configures the version of the string library.
//
// The version limits which functions are available. Only functions introduced
// below or equal to the given version included in the library. If this option
// is not set, all functions are available.
//
// See the library documentation to determine which version a function was introduced.
// If the documentation does not state which version a function was introduced, it can
// be assumed to be introduced at version 0, when the library was first created.
func ListsVersion(version uint32) ListsOption {
return func(lib *listsLib) *listsLib {
lib.version = version
return lib
}
}
// CompileOptions implements the Library interface method.
func (listsLib) CompileOptions() []cel.EnvOption {
func (lib listsLib) CompileOptions() []cel.EnvOption {
listType := cel.ListType(cel.TypeParamType("T"))
return []cel.EnvOption{
listListType := cel.ListType(listType)
listDyn := cel.ListType(cel.DynType)
opts := []cel.EnvOption{
cel.Function("slice",
cel.MemberOverload("list_slice",
[]*cel.Type{listType, cel.IntType, cel.IntType}, listType,
@@ -66,6 +205,151 @@ func (listsLib) CompileOptions() []cel.EnvOption {
),
),
}
if lib.version >= 1 {
opts = append(opts,
cel.Function("flatten",
cel.MemberOverload("list_flatten",
[]*cel.Type{listListType}, listType,
cel.UnaryBinding(func(arg ref.Val) ref.Val {
list, ok := arg.(traits.Lister)
if !ok {
return types.MaybeNoSuchOverloadErr(arg)
}
flatList, err := flatten(list, 1)
if err != nil {
return types.WrapErr(err)
}
return types.DefaultTypeAdapter.NativeToValue(flatList)
}),
),
cel.MemberOverload("list_flatten_int",
[]*cel.Type{listDyn, types.IntType}, listDyn,
cel.BinaryBinding(func(arg1, arg2 ref.Val) ref.Val {
list, ok := arg1.(traits.Lister)
if !ok {
return types.MaybeNoSuchOverloadErr(arg1)
}
depth, ok := arg2.(types.Int)
if !ok {
return types.MaybeNoSuchOverloadErr(arg2)
}
flatList, err := flatten(list, int64(depth))
if err != nil {
return types.WrapErr(err)
}
return types.DefaultTypeAdapter.NativeToValue(flatList)
}),
),
// To handle the case where a variable of just `list(T)` is provided at runtime
// with a graceful failure more, disable the type guards since the implementation
// can handle lists which are already flat.
decls.DisableTypeGuards(true),
),
)
}
if lib.version >= 2 {
sortDecl := cel.Function("sort",
append(
templatedOverloads(comparableTypes, func(t *cel.Type) cel.FunctionOpt {
return cel.MemberOverload(
fmt.Sprintf("list_%s_sort", t.TypeName()),
[]*cel.Type{cel.ListType(t)}, cel.ListType(t),
)
}),
cel.SingletonUnaryBinding(
func(arg ref.Val) ref.Val {
list, ok := arg.(traits.Lister)
if !ok {
return types.MaybeNoSuchOverloadErr(arg)
}
sorted, err := sortList(list)
if err != nil {
return types.WrapErr(err)
}
return sorted
},
// List traits
traits.ListerType,
),
)...,
)
opts = append(opts, sortDecl)
opts = append(opts, cel.Macros(cel.ReceiverMacro("sortBy", 2, sortByMacro)))
opts = append(opts, cel.Function("@sortByAssociatedKeys",
append(
templatedOverloads(comparableTypes, func(u *cel.Type) cel.FunctionOpt {
return cel.MemberOverload(
fmt.Sprintf("list_%s_sortByAssociatedKeys", u.TypeName()),
[]*cel.Type{listType, cel.ListType(u)}, listType,
)
}),
cel.SingletonBinaryBinding(
func(arg1 ref.Val, arg2 ref.Val) ref.Val {
list, ok := arg1.(traits.Lister)
if !ok {
return types.MaybeNoSuchOverloadErr(arg1)
}
keys, ok := arg2.(traits.Lister)
if !ok {
return types.MaybeNoSuchOverloadErr(arg2)
}
sorted, err := sortListByAssociatedKeys(list, keys)
if err != nil {
return types.WrapErr(err)
}
return sorted
},
// List traits
traits.ListerType,
),
)...,
))
opts = append(opts, cel.Function("lists.range",
cel.Overload("lists_range",
[]*cel.Type{cel.IntType}, cel.ListType(cel.IntType),
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
n := args[0].(types.Int)
result, err := genRange(n)
if err != nil {
return types.WrapErr(err)
}
return result
}),
),
))
opts = append(opts, cel.Function("reverse",
cel.MemberOverload("list_reverse",
[]*cel.Type{listType}, listType,
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
list := args[0].(traits.Lister)
result, err := reverseList(list)
if err != nil {
return types.WrapErr(err)
}
return result
}),
),
))
opts = append(opts, cel.Function("distinct",
cel.MemberOverload("list_distinct",
[]*cel.Type{listType}, listType,
cel.UnaryBinding(func(list ref.Val) ref.Val {
result, err := distinctList(list.(traits.Lister))
if err != nil {
return types.WrapErr(err)
}
return result
}),
),
))
}
return opts
}
// ProgramOptions implements the Library interface method.
@@ -73,6 +357,24 @@ func (listsLib) ProgramOptions() []cel.ProgramOption {
return []cel.ProgramOption{}
}
func genRange(n types.Int) (ref.Val, error) {
var newList []ref.Val
for i := types.Int(0); i < n; i++ {
newList = append(newList, i)
}
return types.DefaultTypeAdapter.NativeToValue(newList), nil
}
func reverseList(list traits.Lister) (ref.Val, error) {
var newList []ref.Val
listLength := list.Size().(types.Int)
for i := types.Int(0); i < listLength; i++ {
val := list.Get(listLength - i - 1)
newList = append(newList, val)
}
return types.DefaultTypeAdapter.NativeToValue(newList), nil
}
func slice(list traits.Lister, start, end types.Int) (ref.Val, error) {
listLength := list.Size().(types.Int)
if start < 0 || end < 0 {
@@ -92,3 +394,167 @@ func slice(list traits.Lister, start, end types.Int) (ref.Val, error) {
}
return types.DefaultTypeAdapter.NativeToValue(newList), nil
}
func flatten(list traits.Lister, depth int64) ([]ref.Val, error) {
if depth < 0 {
return nil, fmt.Errorf("level must be non-negative")
}
var newList []ref.Val
iter := list.Iterator()
for iter.HasNext() == types.True {
val := iter.Next()
nestedList, isList := val.(traits.Lister)
if !isList || depth == 0 {
newList = append(newList, val)
continue
} else {
flattenedList, err := flatten(nestedList, depth-1)
if err != nil {
return nil, err
}
newList = append(newList, flattenedList...)
}
}
return newList, nil
}
func sortList(list traits.Lister) (ref.Val, error) {
return sortListByAssociatedKeys(list, list)
}
// Internal function used for the implementation of sort() and sortBy().
//
// Sorts a list of arbitrary elements, according to the order produced by sorting
// another list of comparable elements. If the element type of the keys is not
// comparable or the element types are not the same, the function will produce an error.
//
// <list(T)>.@sortByAssociatedKeys(<list(U)>) -> <list(T)>
// U in {int, uint, double, bool, duration, timestamp, string, bytes}
//
// Example:
//
// ["foo", "bar", "baz"].@sortByAssociatedKeys([3, 1, 2]) // return ["bar", "baz", "foo"]
func sortListByAssociatedKeys(list, keys traits.Lister) (ref.Val, error) {
listLength := list.Size().(types.Int)
keysLength := keys.Size().(types.Int)
if listLength != keysLength {
return nil, fmt.Errorf(
"@sortByAssociatedKeys() expected a list of the same size as the associated keys list, but got %d and %d elements respectively",
listLength,
keysLength,
)
}
if listLength == 0 {
return list, nil
}
elem := keys.Get(types.IntZero)
if _, ok := elem.(traits.Comparer); !ok {
return nil, fmt.Errorf("list elements must be comparable")
}
sortedIndices := make([]ref.Val, 0, listLength)
for i := types.IntZero; i < listLength; i++ {
if keys.Get(i).Type() != elem.Type() {
return nil, fmt.Errorf("list elements must have the same type")
}
sortedIndices = append(sortedIndices, i)
}
sort.Slice(sortedIndices, func(i, j int) bool {
iKey := keys.Get(sortedIndices[i])
jKey := keys.Get(sortedIndices[j])
return iKey.(traits.Comparer).Compare(jKey) == types.IntNegOne
})
sorted := make([]ref.Val, 0, listLength)
for _, sortedIdx := range sortedIndices {
sorted = append(sorted, list.Get(sortedIdx))
}
return types.DefaultTypeAdapter.NativeToValue(sorted), nil
}
// sortByMacro transforms an expression like:
//
// mylistExpr.sortBy(e, -math.abs(e))
//
// into something equivalent to:
//
// cel.bind(
// __sortBy_input__,
// myListExpr,
// __sortBy_input__.@sortByAssociatedKeys(__sortBy_input__.map(e, -math.abs(e))
// )
func sortByMacro(meh cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *cel.Error) {
varIdent := meh.NewIdent("@__sortBy_input__")
varName := varIdent.AsIdent()
targetKind := target.Kind()
if targetKind != ast.ListKind &&
targetKind != ast.SelectKind &&
targetKind != ast.IdentKind &&
targetKind != ast.ComprehensionKind && targetKind != ast.CallKind {
return nil, meh.NewError(target.ID(), fmt.Sprintf("sortBy can only be applied to a list, identifier, comprehension, call or select expression"))
}
mapCompr, err := parser.MakeMap(meh, meh.Copy(varIdent), args)
if err != nil {
return nil, err
}
callExpr := meh.NewMemberCall("@sortByAssociatedKeys",
meh.Copy(varIdent),
mapCompr,
)
bindExpr := meh.NewComprehension(
meh.NewList(),
"#unused",
varName,
target,
meh.NewLiteral(types.False),
varIdent,
callExpr,
)
return bindExpr, nil
}
func distinctList(list traits.Lister) (ref.Val, error) {
listLength := list.Size().(types.Int)
if listLength == 0 {
return list, nil
}
uniqueList := make([]ref.Val, 0, listLength)
for i := types.IntZero; i < listLength; i++ {
val := list.Get(i)
seen := false
for j := types.IntZero; j < types.Int(len(uniqueList)); j++ {
if i == j {
continue
}
other := uniqueList[j]
if val.Equal(other) == types.True {
seen = true
break
}
}
if !seen {
uniqueList = append(uniqueList, val)
}
}
return types.DefaultTypeAdapter.NativeToValue(uniqueList), nil
}
func templatedOverloads(types []*cel.Type, template func(t *cel.Type) cel.FunctionOpt) []cel.FunctionOpt {
overloads := make([]cel.FunctionOpt, len(types))
for i, t := range types {
overloads[i] = template(t)
}
return overloads
}

View File

@@ -16,6 +16,7 @@ package ext
import (
"fmt"
"math"
"strings"
"github.com/google/cel-go/cel"
@@ -86,28 +87,312 @@ import (
// math.least('string') // parse error
// math.least(a, b) // check-time error if a or b is non-numeric
// math.least(dyn('string')) // runtime error
func Math() cel.EnvOption {
return cel.Lib(mathLib{})
//
// # Math.BitOr
//
// Introduced at version: 1
//
// Performs a bitwise-OR operation over two int or uint values.
//
// math.bitOr(<int>, <int>) -> <int>
// math.bitOr(<uint>, <uint>) -> <uint>
//
// Examples:
//
// math.bitOr(1u, 2u) // returns 3u
// math.bitOr(-2, -4) // returns -2
//
// # Math.BitAnd
//
// Introduced at version: 1
//
// Performs a bitwise-AND operation over two int or uint values.
//
// math.bitAnd(<int>, <int>) -> <int>
// math.bitAnd(<uint>, <uint>) -> <uint>
//
// Examples:
//
// math.bitAnd(3u, 2u) // return 2u
// math.bitAnd(3, 5) // returns 3
// math.bitAnd(-3, -5) // returns -7
//
// # Math.BitXor
//
// Introduced at version: 1
//
// math.bitXor(<int>, <int>) -> <int>
// math.bitXor(<uint>, <uint>) -> <uint>
//
// Performs a bitwise-XOR operation over two int or uint values.
//
// Examples:
//
// math.bitXor(3u, 5u) // returns 6u
// math.bitXor(1, 3) // returns 2
//
// # Math.BitNot
//
// Introduced at version: 1
//
// Function which accepts a single int or uint and performs a bitwise-NOT
// ones-complement of the given binary value.
//
// math.bitNot(<int>) -> <int>
// math.bitNot(<uint>) -> <uint>
//
// Examples
//
// math.bitNot(1) // returns -1
// math.bitNot(-1) // return 0
// math.bitNot(0u) // returns 18446744073709551615u
//
// # Math.BitShiftLeft
//
// Introduced at version: 1
//
// Perform a left shift of bits on the first parameter, by the amount of bits
// specified in the second parameter. The first parameter is either a uint or
// an int. The second parameter must be an int.
//
// When the second parameter is 64 or greater, 0 will be always be returned
// since the number of bits shifted is greater than or equal to the total bit
// length of the number being shifted. Negative valued bit shifts will result
// in a runtime error.
//
// math.bitShiftLeft(<int>, <int>) -> <int>
// math.bitShiftLeft(<uint>, <int>) -> <uint>
//
// Examples
//
// math.bitShiftLeft(1, 2) // returns 4
// math.bitShiftLeft(-1, 2) // returns -4
// math.bitShiftLeft(1u, 2) // return 4u
// math.bitShiftLeft(1u, 200) // returns 0u
//
// # Math.BitShiftRight
//
// Introduced at version: 1
//
// Perform a right shift of bits on the first parameter, by the amount of bits
// specified in the second parameter. The first parameter is either a uint or
// an int. The second parameter must be an int.
//
// When the second parameter is 64 or greater, 0 will always be returned since
// the number of bits shifted is greater than or equal to the total bit length
// of the number being shifted. Negative valued bit shifts will result in a
// runtime error.
//
// The sign bit extension will not be preserved for this operation: vacant bits
// on the left are filled with 0.
//
// math.bitShiftRight(<int>, <int>) -> <int>
// math.bitShiftRight(<uint>, <int>) -> <uint>
//
// Examples
//
// math.bitShiftRight(1024, 2) // returns 256
// math.bitShiftRight(1024u, 2) // returns 256u
// math.bitShiftRight(1024u, 64) // returns 0u
//
// # Math.Ceil
//
// Introduced at version: 1
//
// Compute the ceiling of a double value.
//
// math.ceil(<double>) -> <double>
//
// Examples:
//
// math.ceil(1.2) // returns 2.0
// math.ceil(-1.2) // returns -1.0
//
// # Math.Floor
//
// Introduced at version: 1
//
// Compute the floor of a double value.
//
// math.floor(<double>) -> <double>
//
// Examples:
//
// math.floor(1.2) // returns 1.0
// math.floor(-1.2) // returns -2.0
//
// # Math.Round
//
// Introduced at version: 1
//
// Rounds the double value to the nearest whole number with ties rounding away
// from zero, e.g. 1.5 -> 2.0, -1.5 -> -2.0.
//
// math.round(<double>) -> <double>
//
// Examples:
//
// math.round(1.2) // returns 1.0
// math.round(1.5) // returns 2.0
// math.round(-1.5) // returns -2.0
//
// # Math.Trunc
//
// Introduced at version: 1
//
// Truncates the fractional portion of the double value.
//
// math.trunc(<double>) -> <double>
//
// Examples:
//
// math.trunc(-1.3) // returns -1.0
// math.trunc(1.3) // returns 1.0
//
// # Math.Abs
//
// Introduced at version: 1
//
// Returns the absolute value of the numeric type provided as input. If the
// value is NaN, the output is NaN. If the input is int64 min, the function
// will result in an overflow error.
//
// math.abs(<double>) -> <double>
// math.abs(<int>) -> <int>
// math.abs(<uint>) -> <uint>
//
// Examples:
//
// math.abs(-1) // returns 1
// math.abs(1) // returns 1
// math.abs(-9223372036854775808) // overflow error
//
// # Math.Sign
//
// Introduced at version: 1
//
// Returns the sign of the numeric type, either -1, 0, 1 as an int, double, or
// uint depending on the overload. For floating point values, if NaN is
// provided as input, the output is also NaN. The implementation does not
// differentiate between positive and negative zero.
//
// math.sign(<double>) -> <double>
// math.sign(<int>) -> <int>
// math.sign(<uint>) -> <uint>
//
// Examples:
//
// math.sign(-42) // returns -1
// math.sign(0) // returns 0
// math.sign(42) // returns 1
//
// # Math.IsInf
//
// Introduced at version: 1
//
// Returns true if the input double value is -Inf or +Inf.
//
// math.isInf(<double>) -> <bool>
//
// Examples:
//
// math.isInf(1.0/0.0) // returns true
// math.isInf(1.2) // returns false
//
// # Math.IsNaN
//
// Introduced at version: 1
//
// Returns true if the input double value is NaN, false otherwise.
//
// math.isNaN(<double>) -> <bool>
//
// Examples:
//
// math.isNaN(0.0/0.0) // returns true
// math.isNaN(1.2) // returns false
//
// # Math.IsFinite
//
// Introduced at version: 1
//
// Returns true if the value is a finite number. Equivalent in behavior to:
// !math.isNaN(double) && !math.isInf(double)
//
// math.isFinite(<double>) -> <bool>
//
// Examples:
//
// math.isFinite(0.0/0.0) // returns false
// math.isFinite(1.2) // returns true
func Math(options ...MathOption) cel.EnvOption {
m := &mathLib{version: math.MaxUint32}
for _, o := range options {
m = o(m)
}
return cel.Lib(m)
}
const (
mathNamespace = "math"
leastMacro = "least"
greatestMacro = "greatest"
minFunc = "math.@min"
maxFunc = "math.@max"
// Min-max functions
minFunc = "math.@min"
maxFunc = "math.@max"
// Rounding functions
ceilFunc = "math.ceil"
floorFunc = "math.floor"
roundFunc = "math.round"
truncFunc = "math.trunc"
// Floating point helper functions
isInfFunc = "math.isInf"
isNanFunc = "math.isNaN"
isFiniteFunc = "math.isFinite"
// Signedness functions
absFunc = "math.abs"
signFunc = "math.sign"
// Bitwise functions
bitAndFunc = "math.bitAnd"
bitOrFunc = "math.bitOr"
bitXorFunc = "math.bitXor"
bitNotFunc = "math.bitNot"
bitShiftLeftFunc = "math.bitShiftLeft"
bitShiftRightFunc = "math.bitShiftRight"
)
type mathLib struct{}
var (
errIntOverflow = types.NewErr("integer overflow")
)
// MathOption declares a functional operator for configuring math extensions.
type MathOption func(*mathLib) *mathLib
// MathVersion sets the library version for math extensions.
func MathVersion(version uint32) MathOption {
return func(lib *mathLib) *mathLib {
lib.version = version
return lib
}
}
type mathLib struct {
version uint32
}
// LibraryName implements the SingletonLibrary interface method.
func (mathLib) LibraryName() string {
func (*mathLib) LibraryName() string {
return "cel.lib.ext.math"
}
// CompileOptions implements the Library interface method.
func (mathLib) CompileOptions() []cel.EnvOption {
return []cel.EnvOption{
func (lib *mathLib) CompileOptions() []cel.EnvOption {
opts := []cel.EnvOption{
cel.Macros(
// math.least(num, ...)
cel.ReceiverVarArgMacro(leastMacro, mathLeast),
@@ -179,10 +464,95 @@ func (mathLib) CompileOptions() []cel.EnvOption {
cel.UnaryBinding(maxList)),
),
}
if lib.version >= 1 {
opts = append(opts,
// Rounding function declarations
cel.Function(ceilFunc,
cel.Overload("math_ceil_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(ceil))),
cel.Function(floorFunc,
cel.Overload("math_floor_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(floor))),
cel.Function(roundFunc,
cel.Overload("math_round_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(round))),
cel.Function(truncFunc,
cel.Overload("math_trunc_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(trunc))),
// Floating point helpers
cel.Function(isInfFunc,
cel.Overload("math_isInf_double", []*cel.Type{cel.DoubleType}, cel.BoolType,
cel.UnaryBinding(isInf))),
cel.Function(isNanFunc,
cel.Overload("math_isNaN_double", []*cel.Type{cel.DoubleType}, cel.BoolType,
cel.UnaryBinding(isNaN))),
cel.Function(isFiniteFunc,
cel.Overload("math_isFinite_double", []*cel.Type{cel.DoubleType}, cel.BoolType,
cel.UnaryBinding(isFinite))),
// Signedness functions
cel.Function(absFunc,
cel.Overload("math_abs_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(absDouble)),
cel.Overload("math_abs_int", []*cel.Type{cel.IntType}, cel.IntType,
cel.UnaryBinding(absInt)),
cel.Overload("math_abs_uint", []*cel.Type{cel.UintType}, cel.UintType,
cel.UnaryBinding(identity)),
),
cel.Function(signFunc,
cel.Overload("math_sign_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
cel.UnaryBinding(sign)),
cel.Overload("math_sign_int", []*cel.Type{cel.IntType}, cel.IntType,
cel.UnaryBinding(sign)),
cel.Overload("math_sign_uint", []*cel.Type{cel.UintType}, cel.UintType,
cel.UnaryBinding(sign)),
),
// Bitwise operator declarations
cel.Function(bitAndFunc,
cel.Overload("math_bitAnd_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
cel.BinaryBinding(bitAndPairInt)),
cel.Overload("math_bitAnd_uint_uint", []*cel.Type{cel.UintType, cel.UintType}, cel.UintType,
cel.BinaryBinding(bitAndPairUint)),
),
cel.Function(bitOrFunc,
cel.Overload("math_bitOr_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
cel.BinaryBinding(bitOrPairInt)),
cel.Overload("math_bitOr_uint_uint", []*cel.Type{cel.UintType, cel.UintType}, cel.UintType,
cel.BinaryBinding(bitOrPairUint)),
),
cel.Function(bitXorFunc,
cel.Overload("math_bitXor_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
cel.BinaryBinding(bitXorPairInt)),
cel.Overload("math_bitXor_uint_uint", []*cel.Type{cel.UintType, cel.UintType}, cel.UintType,
cel.BinaryBinding(bitXorPairUint)),
),
cel.Function(bitNotFunc,
cel.Overload("math_bitNot_int_int", []*cel.Type{cel.IntType}, cel.IntType,
cel.UnaryBinding(bitNotInt)),
cel.Overload("math_bitNot_uint_uint", []*cel.Type{cel.UintType}, cel.UintType,
cel.UnaryBinding(bitNotUint)),
),
cel.Function(bitShiftLeftFunc,
cel.Overload("math_bitShiftLeft_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
cel.BinaryBinding(bitShiftLeftIntInt)),
cel.Overload("math_bitShiftLeft_uint_int", []*cel.Type{cel.UintType, cel.IntType}, cel.UintType,
cel.BinaryBinding(bitShiftLeftUintInt)),
),
cel.Function(bitShiftRightFunc,
cel.Overload("math_bitShiftRight_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
cel.BinaryBinding(bitShiftRightIntInt)),
cel.Overload("math_bitShiftRight_uint_int", []*cel.Type{cel.UintType, cel.IntType}, cel.UintType,
cel.BinaryBinding(bitShiftRightUintInt)),
),
)
}
return opts
}
// ProgramOptions implements the Library interface method.
func (mathLib) ProgramOptions() []cel.ProgramOption {
func (*mathLib) ProgramOptions() []cel.ProgramOption {
return []cel.ProgramOption{}
}
@@ -194,7 +564,7 @@ func mathLeast(meh cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.
case 0:
return nil, meh.NewError(target.ID(), "math.least() requires at least one argument")
case 1:
if isListLiteralWithValidArgs(args[0]) || isValidArgType(args[0]) {
if isListLiteralWithNumericArgs(args[0]) || isNumericArgType(args[0]) {
return meh.NewCall(minFunc, args[0]), nil
}
return nil, meh.NewError(args[0].ID(), "math.least() invalid single argument value")
@@ -221,7 +591,7 @@ func mathGreatest(mef cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (a
case 0:
return nil, mef.NewError(target.ID(), "math.greatest() requires at least one argument")
case 1:
if isListLiteralWithValidArgs(args[0]) || isValidArgType(args[0]) {
if isListLiteralWithNumericArgs(args[0]) || isNumericArgType(args[0]) {
return mef.NewCall(maxFunc, args[0]), nil
}
return nil, mef.NewError(args[0].ID(), "math.greatest() invalid single argument value")
@@ -244,6 +614,165 @@ func identity(val ref.Val) ref.Val {
return val
}
func ceil(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Double(math.Ceil(float64(v)))
}
func floor(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Double(math.Floor(float64(v)))
}
func round(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Double(math.Round(float64(v)))
}
func trunc(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Double(math.Trunc(float64(v)))
}
func isInf(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Bool(math.IsInf(float64(v), 0))
}
func isFinite(val ref.Val) ref.Val {
v := float64(val.(types.Double))
return types.Bool(!math.IsInf(v, 0) && !math.IsNaN(v))
}
func isNaN(val ref.Val) ref.Val {
v := val.(types.Double)
return types.Bool(math.IsNaN(float64(v)))
}
func absDouble(val ref.Val) ref.Val {
v := float64(val.(types.Double))
return types.Double(math.Abs(v))
}
func absInt(val ref.Val) ref.Val {
v := int64(val.(types.Int))
if v == math.MinInt64 {
return errIntOverflow
}
if v >= 0 {
return val
}
return -types.Int(v)
}
func sign(val ref.Val) ref.Val {
switch v := val.(type) {
case types.Double:
if isNaN(v) == types.True {
return v
}
zero := types.Double(0)
if v > zero {
return types.Double(1)
}
if v < zero {
return types.Double(-1)
}
return zero
case types.Int:
return v.Compare(types.IntZero)
case types.Uint:
if v == types.Uint(0) {
return types.Uint(0)
}
return types.Uint(1)
default:
return maybeSuffixError(val, "math.sign")
}
}
func bitAndPairInt(first, second ref.Val) ref.Val {
l := first.(types.Int)
r := second.(types.Int)
return l & r
}
func bitAndPairUint(first, second ref.Val) ref.Val {
l := first.(types.Uint)
r := second.(types.Uint)
return l & r
}
func bitOrPairInt(first, second ref.Val) ref.Val {
l := first.(types.Int)
r := second.(types.Int)
return l | r
}
func bitOrPairUint(first, second ref.Val) ref.Val {
l := first.(types.Uint)
r := second.(types.Uint)
return l | r
}
func bitXorPairInt(first, second ref.Val) ref.Val {
l := first.(types.Int)
r := second.(types.Int)
return l ^ r
}
func bitXorPairUint(first, second ref.Val) ref.Val {
l := first.(types.Uint)
r := second.(types.Uint)
return l ^ r
}
func bitNotInt(value ref.Val) ref.Val {
v := value.(types.Int)
return ^v
}
func bitNotUint(value ref.Val) ref.Val {
v := value.(types.Uint)
return ^v
}
func bitShiftLeftIntInt(value, bits ref.Val) ref.Val {
v := value.(types.Int)
bs := bits.(types.Int)
if bs < types.IntZero {
return types.NewErr("math.bitShiftLeft() negative offset: %d", bs)
}
return v << bs
}
func bitShiftLeftUintInt(value, bits ref.Val) ref.Val {
v := value.(types.Uint)
bs := bits.(types.Int)
if bs < types.IntZero {
return types.NewErr("math.bitShiftLeft() negative offset: %d", bs)
}
return v << bs
}
func bitShiftRightIntInt(value, bits ref.Val) ref.Val {
v := value.(types.Int)
bs := bits.(types.Int)
if bs < types.IntZero {
return types.NewErr("math.bitShiftRight() negative offset: %d", bs)
}
return types.Int(types.Uint(v) >> bs)
}
func bitShiftRightUintInt(value, bits ref.Val) ref.Val {
v := value.(types.Uint)
bs := bits.(types.Int)
if bs < types.IntZero {
return types.NewErr("math.bitShiftRight() negative offset: %d", bs)
}
return v >> bs
}
func minPair(first, second ref.Val) ref.Val {
cmp, ok := first.(traits.Comparer)
if !ok {
@@ -321,13 +850,13 @@ func checkInvalidArgs(meh cel.MacroExprFactory, funcName string, args []ast.Expr
}
func checkInvalidArgLiteral(funcName string, arg ast.Expr) error {
if !isValidArgType(arg) {
if !isNumericArgType(arg) {
return fmt.Errorf("%s simple literal arguments must be numeric", funcName)
}
return nil
}
func isValidArgType(arg ast.Expr) bool {
func isNumericArgType(arg ast.Expr) bool {
switch arg.Kind() {
case ast.LiteralKind:
c := ref.Val(arg.AsLiteral())
@@ -344,7 +873,7 @@ func isValidArgType(arg ast.Expr) bool {
}
}
func isListLiteralWithValidArgs(arg ast.Expr) bool {
func isListLiteralWithNumericArgs(arg ast.Expr) bool {
switch arg.Kind() {
case ast.ListKind:
list := arg.AsList()
@@ -352,7 +881,7 @@ func isListLiteralWithValidArgs(arg ast.Expr) bool {
return false
}
for _, e := range list.Elements() {
if !isValidArgType(e) {
if !isNumericArgType(e) {
return false
}
}

View File

@@ -15,6 +15,7 @@
package ext
import (
"errors"
"fmt"
"reflect"
"strings"
@@ -77,12 +78,45 @@ var (
// same advice holds if you are using custom type adapters and type providers. The native type
// provider composes over whichever type adapter and provider is configured in the cel.Env at
// the time that it is invoked.
func NativeTypes(refTypes ...any) cel.EnvOption {
//
// There is also the possibility to rename the fields of native structs by setting the `cel` tag
// for fields you want to override. In order to enable this feature, pass in the `EnableStructTag`
// option. Here is an example to see it in action:
//
// ```go
// package identity
//
// type Account struct {
// ID int
// OwnerName string `cel:"owner"`
// }
//
// ```
//
// The `OwnerName` field is now accessible in CEL via `owner`, e.g. `identity.Account{owner: 'bob'}`.
// In case there are duplicated field names in the struct, an error will be returned.
func NativeTypes(args ...any) cel.EnvOption {
return func(env *cel.Env) (*cel.Env, error) {
tp, err := newNativeTypeProvider(env.CELTypeAdapter(), env.CELTypeProvider(), refTypes...)
nativeTypes := make([]any, 0, len(args))
tpOptions := nativeTypeOptions{}
for _, v := range args {
switch v := v.(type) {
case NativeTypesOption:
err := v(&tpOptions)
if err != nil {
return nil, err
}
default:
nativeTypes = append(nativeTypes, v)
}
}
tp, err := newNativeTypeProvider(tpOptions, env.CELTypeAdapter(), env.CELTypeProvider(), nativeTypes...)
if err != nil {
return nil, err
}
env, err = cel.CustomTypeAdapter(tp)(env)
if err != nil {
return nil, err
@@ -91,12 +125,79 @@ func NativeTypes(refTypes ...any) cel.EnvOption {
}
}
func newNativeTypeProvider(adapter types.Adapter, provider types.Provider, refTypes ...any) (*nativeTypeProvider, error) {
// NativeTypesOption is a functional interface for configuring handling of native types.
type NativeTypesOption func(*nativeTypeOptions) error
// NativeTypesFieldNameHandler is a handler for mapping a reflect.StructField to a CEL field name.
// This can be used to override the default Go struct field to CEL field name mapping.
type NativeTypesFieldNameHandler = func(field reflect.StructField) string
func fieldNameByTag(structTagToParse string) func(field reflect.StructField) string {
return func(field reflect.StructField) string {
tag, found := field.Tag.Lookup(structTagToParse)
if found {
splits := strings.Split(tag, ",")
if len(splits) > 0 {
// We make the assumption that the leftmost entry in the tag is the name.
// This seems to be true for most tags that have the concept of a name/key, such as:
// https://pkg.go.dev/encoding/xml#Marshal
// https://pkg.go.dev/encoding/json#Marshal
// https://pkg.go.dev/go.mongodb.org/mongo-driver/bson#hdr-Structs
// https://pkg.go.dev/gopkg.in/yaml.v2#Marshal
name := splits[0]
return name
}
}
return field.Name
}
}
type nativeTypeOptions struct {
// fieldNameHandler controls how CEL should perform struct field renames.
// This is most commonly used for switching to parsing based off the struct field tag,
// such as "cel" or "json".
fieldNameHandler NativeTypesFieldNameHandler
}
// ParseStructTags configures if native types field names should be overridable by CEL struct tags.
// This is equivalent to ParseStructTag("cel")
func ParseStructTags(enabled bool) NativeTypesOption {
return func(ntp *nativeTypeOptions) error {
if enabled {
ntp.fieldNameHandler = fieldNameByTag("cel")
} else {
ntp.fieldNameHandler = nil
}
return nil
}
}
// ParseStructTag configures the struct tag to parse. The 0th item in the tag is used as the name of the CEL field.
// For example:
// If the tag to parse is "cel" and the struct field has tag cel:"foo", the CEL struct field will be "foo".
// If the tag to parse is "json" and the struct field has tag json:"foo,omitempty", the CEL struct field will be "foo".
func ParseStructTag(tag string) NativeTypesOption {
return func(ntp *nativeTypeOptions) error {
ntp.fieldNameHandler = fieldNameByTag(tag)
return nil
}
}
// ParseStructField configures how to parse Go struct fields. It can be used to customize struct field parsing.
func ParseStructField(handler NativeTypesFieldNameHandler) NativeTypesOption {
return func(ntp *nativeTypeOptions) error {
ntp.fieldNameHandler = handler
return nil
}
}
func newNativeTypeProvider(tpOptions nativeTypeOptions, adapter types.Adapter, provider types.Provider, refTypes ...any) (*nativeTypeProvider, error) {
nativeTypes := make(map[string]*nativeType, len(refTypes))
for _, refType := range refTypes {
switch rt := refType.(type) {
case reflect.Type:
result, err := newNativeTypes(rt)
result, err := newNativeTypes(tpOptions.fieldNameHandler, rt)
if err != nil {
return nil, err
}
@@ -104,7 +205,7 @@ func newNativeTypeProvider(adapter types.Adapter, provider types.Provider, refTy
nativeTypes[result[idx].TypeName()] = result[idx]
}
case reflect.Value:
result, err := newNativeTypes(rt.Type())
result, err := newNativeTypes(tpOptions.fieldNameHandler, rt.Type())
if err != nil {
return nil, err
}
@@ -119,6 +220,7 @@ func newNativeTypeProvider(adapter types.Adapter, provider types.Provider, refTy
nativeTypes: nativeTypes,
baseAdapter: adapter,
baseProvider: provider,
options: tpOptions,
}, nil
}
@@ -126,6 +228,7 @@ type nativeTypeProvider struct {
nativeTypes map[string]*nativeType
baseAdapter types.Adapter
baseProvider types.Provider
options nativeTypeOptions
}
// EnumValue proxies to the types.Provider configured at the times the NativeTypes
@@ -155,6 +258,14 @@ func (tp *nativeTypeProvider) FindStructType(typeName string) (*types.Type, bool
return tp.baseProvider.FindStructType(typeName)
}
func toFieldName(fieldNameHandler NativeTypesFieldNameHandler, f reflect.StructField) string {
if fieldNameHandler == nil {
return f.Name
}
return fieldNameHandler(f)
}
// FindStructFieldNames looks up the type definition first from the native types, then from
// the backing provider type set. If found, a set of field names corresponding to the type
// will be returned.
@@ -163,7 +274,7 @@ func (tp *nativeTypeProvider) FindStructFieldNames(typeName string) ([]string, b
fieldCount := t.refType.NumField()
fields := make([]string, fieldCount)
for i := 0; i < fieldCount; i++ {
fields[i] = t.refType.Field(i).Name
fields[i] = toFieldName(tp.options.fieldNameHandler, t.refType.Field(i))
}
return fields, true
}
@@ -192,13 +303,13 @@ func (tp *nativeTypeProvider) FindStructFieldType(typeName, fieldName string) (*
Type: celType,
IsSet: func(obj any) bool {
refVal := reflect.Indirect(reflect.ValueOf(obj))
refField := refVal.FieldByName(fieldName)
refField := refVal.FieldByName(refField.Name)
return !refField.IsZero()
},
GetFrom: func(obj any) (any, error) {
refVal := reflect.Indirect(reflect.ValueOf(obj))
refField := refVal.FieldByName(fieldName)
return getFieldValue(tp, refField), nil
refField := refVal.FieldByName(refField.Name)
return getFieldValue(refField), nil
},
}, true
}
@@ -249,6 +360,9 @@ func (tp *nativeTypeProvider) NativeToValue(val any) ref.Val {
case []byte:
return tp.baseAdapter.NativeToValue(val)
default:
if refVal.Type().Elem() == reflect.TypeOf(byte(0)) {
return tp.baseAdapter.NativeToValue(val)
}
return types.NewDynamicList(tp, val)
}
case reflect.Map:
@@ -259,7 +373,7 @@ func (tp *nativeTypeProvider) NativeToValue(val any) ref.Val {
time.Time:
return tp.baseAdapter.NativeToValue(val)
default:
return newNativeObject(tp, val, rawVal)
return tp.newNativeObject(val, rawVal)
}
default:
return tp.baseAdapter.NativeToValue(val)
@@ -319,13 +433,13 @@ func convertToCelType(refType reflect.Type) (*cel.Type, bool) {
return nil, false
}
func newNativeObject(adapter types.Adapter, val any, refValue reflect.Value) ref.Val {
valType, err := newNativeType(refValue.Type())
func (tp *nativeTypeProvider) newNativeObject(val any, refValue reflect.Value) ref.Val {
valType, err := newNativeType(tp.options.fieldNameHandler, refValue.Type())
if err != nil {
return types.NewErr(err.Error())
}
return &nativeObj{
Adapter: adapter,
Adapter: tp,
val: val,
valType: valType,
refValue: refValue,
@@ -372,12 +486,13 @@ func (o *nativeObj) ConvertToNative(typeDesc reflect.Type) (any, error) {
if !fieldValue.IsValid() || fieldValue.IsZero() {
continue
}
fieldName := toFieldName(o.valType.fieldNameHandler, fieldType)
fieldCELVal := o.NativeToValue(fieldValue.Interface())
fieldJSONVal, err := fieldCELVal.ConvertToNative(jsonValueType)
if err != nil {
return nil, err
}
fields[fieldType.Name] = fieldJSONVal.(*structpb.Value)
fields[fieldName] = fieldJSONVal.(*structpb.Value)
}
return &structpb.Struct{Fields: fields}, nil
}
@@ -469,8 +584,8 @@ func (o *nativeObj) Value() any {
return o.val
}
func newNativeTypes(rawType reflect.Type) ([]*nativeType, error) {
nt, err := newNativeType(rawType)
func newNativeTypes(fieldNameHandler NativeTypesFieldNameHandler, rawType reflect.Type) ([]*nativeType, error) {
nt, err := newNativeType(fieldNameHandler, rawType)
if err != nil {
return nil, err
}
@@ -489,7 +604,7 @@ func newNativeTypes(rawType reflect.Type) ([]*nativeType, error) {
return
}
alreadySeen[t.String()] = struct{}{}
nt, ntErr := newNativeType(t)
nt, ntErr := newNativeType(fieldNameHandler, t)
if ntErr != nil {
err = ntErr
return
@@ -505,7 +620,11 @@ func newNativeTypes(rawType reflect.Type) ([]*nativeType, error) {
return result, err
}
func newNativeType(rawType reflect.Type) (*nativeType, error) {
var (
errDuplicatedFieldName = errors.New("field name already exists in struct")
)
func newNativeType(fieldNameHandler NativeTypesFieldNameHandler, rawType reflect.Type) (*nativeType, error) {
refType := rawType
if refType.Kind() == reflect.Pointer {
refType = refType.Elem()
@@ -513,15 +632,34 @@ func newNativeType(rawType reflect.Type) (*nativeType, error) {
if !isValidObjectType(refType) {
return nil, fmt.Errorf("unsupported reflect.Type %v, must be reflect.Struct", rawType)
}
// Since naming collisions can only happen with struct tag parsing, we only check for them if it is enabled.
if fieldNameHandler != nil {
fieldNames := make(map[string]struct{})
for idx := 0; idx < refType.NumField(); idx++ {
field := refType.Field(idx)
fieldName := toFieldName(fieldNameHandler, field)
if _, found := fieldNames[fieldName]; found {
return nil, fmt.Errorf("invalid field name `%s` in struct `%s`: %w", fieldName, refType.Name(), errDuplicatedFieldName)
} else {
fieldNames[fieldName] = struct{}{}
}
}
}
return &nativeType{
typeName: fmt.Sprintf("%s.%s", simplePkgAlias(refType.PkgPath()), refType.Name()),
refType: refType,
typeName: fmt.Sprintf("%s.%s", simplePkgAlias(refType.PkgPath()), refType.Name()),
refType: refType,
fieldNameHandler: fieldNameHandler,
}, nil
}
type nativeType struct {
typeName string
refType reflect.Type
typeName string
refType reflect.Type
fieldNameHandler NativeTypesFieldNameHandler
}
// ConvertToNative implements ref.Val.ConvertToNative.
@@ -569,9 +707,26 @@ func (t *nativeType) Value() any {
return t.typeName
}
// fieldByName returns the corresponding reflect.StructField for the give name either by matching
// field tag or field name.
func (t *nativeType) fieldByName(fieldName string) (reflect.StructField, bool) {
if t.fieldNameHandler == nil {
return t.refType.FieldByName(fieldName)
}
for i := 0; i < t.refType.NumField(); i++ {
f := t.refType.Field(i)
if toFieldName(t.fieldNameHandler, f) == fieldName {
return f, true
}
}
return reflect.StructField{}, false
}
// hasField returns whether a field name has a corresponding Golang reflect.StructField
func (t *nativeType) hasField(fieldName string) (reflect.StructField, bool) {
f, found := t.refType.FieldByName(fieldName)
f, found := t.fieldByName(fieldName)
if !found || !f.IsExported() || !isSupportedType(f.Type) {
return reflect.StructField{}, false
}
@@ -579,21 +734,16 @@ func (t *nativeType) hasField(fieldName string) (reflect.StructField, bool) {
}
func adaptFieldValue(adapter types.Adapter, refField reflect.Value) ref.Val {
return adapter.NativeToValue(getFieldValue(adapter, refField))
return adapter.NativeToValue(getFieldValue(refField))
}
func getFieldValue(adapter types.Adapter, refField reflect.Value) any {
func getFieldValue(refField reflect.Value) any {
if refField.IsZero() {
switch refField.Kind() {
case reflect.Array, reflect.Slice:
return types.NewDynamicList(adapter, []ref.Val{})
case reflect.Map:
return types.NewDynamicMap(adapter, map[ref.Val]ref.Val{})
case reflect.Struct:
if refField.Type() == timestampType {
return types.Timestamp{Time: time.Unix(0, 0)}
return time.Unix(0, 0)
}
return reflect.New(refField.Type()).Elem().Interface()
case reflect.Pointer:
return reflect.New(refField.Type().Elem()).Interface()
}

View File

@@ -119,7 +119,8 @@ const (
// 'hello mellow'.indexOf('jello') // returns -1
// 'hello mellow'.indexOf('', 2) // returns 2
// 'hello mellow'.indexOf('ello', 2) // returns 7
// 'hello mellow'.indexOf('ello', 20) // error
// 'hello mellow'.indexOf('ello', 20) // returns -1
// 'hello mellow'.indexOf('ello', -1) // error
//
// # Join
//
@@ -155,6 +156,7 @@ const (
// 'hello mellow'.lastIndexOf('ello') // returns 7
// 'hello mellow'.lastIndexOf('jello') // returns -1
// 'hello mellow'.lastIndexOf('ello', 6) // returns 1
// 'hello mellow'.lastIndexOf('ello', 20) // returns -1
// 'hello mellow'.lastIndexOf('ello', -1) // error
//
// # LowerAscii
@@ -520,7 +522,7 @@ func (lib *stringLib) CompileOptions() []cel.EnvOption {
if lib.version >= 3 {
opts = append(opts,
cel.Function("reverse",
cel.MemberOverload("reverse", []*cel.Type{cel.StringType}, cel.StringType,
cel.MemberOverload("string_reverse", []*cel.Type{cel.StringType}, cel.StringType,
cel.UnaryBinding(func(str ref.Val) ref.Val {
s := str.(types.String)
return stringOrError(reverse(string(s)))
@@ -561,9 +563,13 @@ func indexOfOffset(str, substr string, offset int64) (int64, error) {
off := int(offset)
runes := []rune(str)
subrunes := []rune(substr)
if off < 0 || off >= len(runes) {
if off < 0 {
return -1, fmt.Errorf("index out of range: %d", off)
}
// If the offset exceeds the length, return -1 rather than error.
if off >= len(runes) {
return -1, nil
}
for i := off; i < len(runes)-(len(subrunes)-1); i++ {
found := true
for j := 0; j < len(subrunes); j++ {
@@ -594,9 +600,13 @@ func lastIndexOfOffset(str, substr string, offset int64) (int64, error) {
off := int(offset)
runes := []rune(str)
subrunes := []rune(substr)
if off < 0 || off >= len(runes) {
if off < 0 {
return -1, fmt.Errorf("index out of range: %d", off)
}
// If the offset is far greater than the length return -1
if off >= len(runes) {
return -1, nil
}
if off > len(runes)-len(subrunes) {
off = len(runes) - len(subrunes)
}

View File

@@ -17,7 +17,6 @@ package interpreter
import (
"errors"
"fmt"
"sync"
"github.com/google/cel-go/common/types/ref"
)
@@ -167,35 +166,3 @@ type partActivation struct {
func (a *partActivation) UnknownAttributePatterns() []*AttributePattern {
return a.unknowns
}
// varActivation represents a single mutable variable binding.
//
// This activation type should only be used within folds as the fold loop controls the object
// life-cycle.
type varActivation struct {
parent Activation
name string
val ref.Val
}
// Parent implements the Activation interface method.
func (v *varActivation) Parent() Activation {
return v.parent
}
// ResolveName implements the Activation interface method.
func (v *varActivation) ResolveName(name string) (any, bool) {
if name == v.name {
return v.val, true
}
return v.parent.ResolveName(name)
}
var (
// pool of var activations to reduce allocations during folds.
varActivationPool = &sync.Pool{
New: func() any {
return &varActivation{}
},
}
)

View File

@@ -178,10 +178,8 @@ func numericValueEquals(value any, celValue ref.Val) bool {
// NewPartialAttributeFactory returns an AttributeFactory implementation capable of performing
// AttributePattern matches with PartialActivation inputs.
func NewPartialAttributeFactory(container *containers.Container,
adapter types.Adapter,
provider types.Provider) AttributeFactory {
fac := NewAttributeFactory(container, adapter, provider)
func NewPartialAttributeFactory(container *containers.Container, adapter types.Adapter, provider types.Provider, opts ...AttrFactoryOption) AttributeFactory {
fac := NewAttributeFactory(container, adapter, provider, opts...)
return &partialAttributeFactory{
AttributeFactory: fac,
container: container,

View File

@@ -126,21 +126,39 @@ type NamespacedAttribute interface {
Qualifiers() []Qualifier
}
// AttrFactoryOption specifies a functional option for configuring an attribute factory.
type AttrFactoryOption func(*attrFactory) *attrFactory
// EnableErrorOnBadPresenceTest error generation when a presence test or optional field selection
// is performed on a primitive type.
func EnableErrorOnBadPresenceTest(value bool) AttrFactoryOption {
return func(fac *attrFactory) *attrFactory {
fac.errorOnBadPresenceTest = value
return fac
}
}
// NewAttributeFactory returns a default AttributeFactory which is produces Attribute values
// capable of resolving types by simple names and qualify the values using the supported qualifier
// types: bool, int, string, and uint.
func NewAttributeFactory(cont *containers.Container, a types.Adapter, p types.Provider) AttributeFactory {
return &attrFactory{
func NewAttributeFactory(cont *containers.Container, a types.Adapter, p types.Provider, opts ...AttrFactoryOption) AttributeFactory {
fac := &attrFactory{
container: cont,
adapter: a,
provider: p,
}
for _, o := range opts {
fac = o(fac)
}
return fac
}
type attrFactory struct {
container *containers.Container
adapter types.Adapter
provider types.Provider
errorOnBadPresenceTest bool
}
// AbsoluteAttribute refers to a variable value and an optional qualifier path.
@@ -149,12 +167,13 @@ type attrFactory struct {
// resolution rules.
func (r *attrFactory) AbsoluteAttribute(id int64, names ...string) NamespacedAttribute {
return &absoluteAttribute{
id: id,
namespaceNames: names,
qualifiers: []Qualifier{},
adapter: r.adapter,
provider: r.provider,
fac: r,
id: id,
namespaceNames: names,
qualifiers: []Qualifier{},
adapter: r.adapter,
provider: r.provider,
fac: r,
errorOnBadPresenceTest: r.errorOnBadPresenceTest,
}
}
@@ -188,11 +207,12 @@ func (r *attrFactory) MaybeAttribute(id int64, name string) Attribute {
// RelativeAttribute refers to an expression and an optional qualifier path.
func (r *attrFactory) RelativeAttribute(id int64, operand Interpretable) Attribute {
return &relativeAttribute{
id: id,
operand: operand,
qualifiers: []Qualifier{},
adapter: r.adapter,
fac: r,
id: id,
operand: operand,
qualifiers: []Qualifier{},
adapter: r.adapter,
fac: r,
errorOnBadPresenceTest: r.errorOnBadPresenceTest,
}
}
@@ -214,7 +234,7 @@ func (r *attrFactory) NewQualifier(objType *types.Type, qualID int64, val any, o
}, nil
}
}
return newQualifier(r.adapter, qualID, val, opt)
return newQualifier(r.adapter, qualID, val, opt, r.errorOnBadPresenceTest)
}
type absoluteAttribute struct {
@@ -226,6 +246,8 @@ type absoluteAttribute struct {
adapter types.Adapter
provider types.Provider
fac AttributeFactory
errorOnBadPresenceTest bool
}
// ID implements the Attribute interface method.
@@ -514,6 +536,8 @@ type relativeAttribute struct {
qualifiers []Qualifier
adapter types.Adapter
fac AttributeFactory
errorOnBadPresenceTest bool
}
// ID is an implementation of the Attribute interface method.
@@ -577,7 +601,7 @@ func (a *relativeAttribute) String() string {
return fmt.Sprintf("id: %v, operand: %v", a.id, a.operand)
}
func newQualifier(adapter types.Adapter, id int64, v any, opt bool) (Qualifier, error) {
func newQualifier(adapter types.Adapter, id int64, v any, opt, errorOnBadPresenceTest bool) (Qualifier, error) {
var qual Qualifier
switch val := v.(type) {
case Attribute:
@@ -592,71 +616,138 @@ func newQualifier(adapter types.Adapter, id int64, v any, opt bool) (Qualifier,
}, nil
case string:
qual = &stringQualifier{
id: id,
value: val,
celValue: types.String(val),
adapter: adapter,
optional: opt,
id: id,
value: val,
celValue: types.String(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case int:
qual = &intQualifier{
id: id, value: int64(val), celValue: types.Int(val), adapter: adapter, optional: opt,
id: id,
value: int64(val),
celValue: types.Int(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case int32:
qual = &intQualifier{
id: id, value: int64(val), celValue: types.Int(val), adapter: adapter, optional: opt,
id: id,
value: int64(val),
celValue: types.Int(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case int64:
qual = &intQualifier{
id: id, value: val, celValue: types.Int(val), adapter: adapter, optional: opt,
id: id,
value: val,
celValue: types.Int(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case uint:
qual = &uintQualifier{
id: id, value: uint64(val), celValue: types.Uint(val), adapter: adapter, optional: opt,
id: id,
value: uint64(val),
celValue: types.Uint(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case uint32:
qual = &uintQualifier{
id: id, value: uint64(val), celValue: types.Uint(val), adapter: adapter, optional: opt,
id: id,
value: uint64(val),
celValue: types.Uint(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case uint64:
qual = &uintQualifier{
id: id, value: val, celValue: types.Uint(val), adapter: adapter, optional: opt,
id: id,
value: val,
celValue: types.Uint(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case bool:
qual = &boolQualifier{
id: id, value: val, celValue: types.Bool(val), adapter: adapter, optional: opt,
id: id,
value: val,
celValue: types.Bool(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case float32:
qual = &doubleQualifier{
id: id,
value: float64(val),
celValue: types.Double(val),
adapter: adapter,
optional: opt,
id: id,
value: float64(val),
celValue: types.Double(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case float64:
qual = &doubleQualifier{
id: id, value: val, celValue: types.Double(val), adapter: adapter, optional: opt,
id: id,
value: val,
celValue: types.Double(val),
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case types.String:
qual = &stringQualifier{
id: id, value: string(val), celValue: val, adapter: adapter, optional: opt,
id: id,
value: string(val),
celValue: val,
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case types.Int:
qual = &intQualifier{
id: id, value: int64(val), celValue: val, adapter: adapter, optional: opt,
id: id,
value: int64(val),
celValue: val,
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case types.Uint:
qual = &uintQualifier{
id: id, value: uint64(val), celValue: val, adapter: adapter, optional: opt,
id: id,
value: uint64(val),
celValue: val,
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case types.Bool:
qual = &boolQualifier{
id: id, value: bool(val), celValue: val, adapter: adapter, optional: opt,
id: id,
value: bool(val),
celValue: val,
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case types.Double:
qual = &doubleQualifier{
id: id, value: float64(val), celValue: val, adapter: adapter, optional: opt,
id: id,
value: float64(val),
celValue: val,
adapter: adapter,
optional: opt,
errorOnBadPresenceTest: errorOnBadPresenceTest,
}
case *types.Unknown:
qual = &unknownQualifier{id: id, value: val}
@@ -687,11 +778,12 @@ func (q *attrQualifier) IsOptional() bool {
}
type stringQualifier struct {
id int64
value string
celValue ref.Val
adapter types.Adapter
optional bool
id int64
value string
celValue ref.Val
adapter types.Adapter
optional bool
errorOnBadPresenceTest bool
}
// ID is an implementation of the Qualifier interface method.
@@ -774,7 +866,7 @@ func (q *stringQualifier) qualifyInternal(vars Activation, obj any, presenceTest
return obj, true, nil
}
default:
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly)
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly, q.errorOnBadPresenceTest)
}
if presenceTest {
return nil, false, nil
@@ -788,11 +880,12 @@ func (q *stringQualifier) Value() ref.Val {
}
type intQualifier struct {
id int64
value int64
celValue ref.Val
adapter types.Adapter
optional bool
id int64
value int64
celValue ref.Val
adapter types.Adapter
optional bool
errorOnBadPresenceTest bool
}
// ID is an implementation of the Qualifier interface method.
@@ -898,7 +991,7 @@ func (q *intQualifier) qualifyInternal(vars Activation, obj any, presenceTest, p
return o[i], true, nil
}
default:
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly)
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly, q.errorOnBadPresenceTest)
}
if presenceTest {
return nil, false, nil
@@ -915,11 +1008,12 @@ func (q *intQualifier) Value() ref.Val {
}
type uintQualifier struct {
id int64
value uint64
celValue ref.Val
adapter types.Adapter
optional bool
id int64
value uint64
celValue ref.Val
adapter types.Adapter
optional bool
errorOnBadPresenceTest bool
}
// ID is an implementation of the Qualifier interface method.
@@ -966,7 +1060,7 @@ func (q *uintQualifier) qualifyInternal(vars Activation, obj any, presenceTest,
return obj, true, nil
}
default:
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly)
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly, q.errorOnBadPresenceTest)
}
if presenceTest {
return nil, false, nil
@@ -980,11 +1074,12 @@ func (q *uintQualifier) Value() ref.Val {
}
type boolQualifier struct {
id int64
value bool
celValue ref.Val
adapter types.Adapter
optional bool
id int64
value bool
celValue ref.Val
adapter types.Adapter
optional bool
errorOnBadPresenceTest bool
}
// ID is an implementation of the Qualifier interface method.
@@ -1017,7 +1112,7 @@ func (q *boolQualifier) qualifyInternal(vars Activation, obj any, presenceTest,
return obj, true, nil
}
default:
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly)
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly, q.errorOnBadPresenceTest)
}
if presenceTest {
return nil, false, nil
@@ -1092,11 +1187,12 @@ func (q *fieldQualifier) Value() ref.Val {
// type may not be known ahead of time and may not conform to the standard types supported as valid
// protobuf map key types.
type doubleQualifier struct {
id int64
value float64
celValue ref.Val
adapter types.Adapter
optional bool
id int64
value float64
celValue ref.Val
adapter types.Adapter
optional bool
errorOnBadPresenceTest bool
}
// ID is an implementation of the Qualifier interface method.
@@ -1120,7 +1216,7 @@ func (q *doubleQualifier) QualifyIfPresent(vars Activation, obj any, presenceOnl
}
func (q *doubleQualifier) qualifyInternal(vars Activation, obj any, presenceTest, presenceOnly bool) (any, bool, error) {
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly)
return refQualify(q.adapter, obj, q.celValue, presenceTest, presenceOnly, q.errorOnBadPresenceTest)
}
// Value implements the ConstantQualifier interface
@@ -1226,7 +1322,7 @@ func attrQualifyIfPresent(fac AttributeFactory, vars Activation, obj any, qualAt
// refQualify attempts to convert the value to a CEL value and then uses reflection methods to try and
// apply the qualifier with the option to presence test field accesses before retrieving field values.
func refQualify(adapter types.Adapter, obj any, idx ref.Val, presenceTest, presenceOnly bool) (ref.Val, bool, error) {
func refQualify(adapter types.Adapter, obj any, idx ref.Val, presenceTest, presenceOnly, errorOnBadPresenceTest bool) (ref.Val, bool, error) {
celVal := adapter.NativeToValue(obj)
switch v := celVal.(type) {
case *types.Unknown:
@@ -1283,7 +1379,7 @@ func refQualify(adapter types.Adapter, obj any, idx ref.Val, presenceTest, prese
}
return val, true, nil
default:
if presenceTest {
if presenceTest && !errorOnBadPresenceTest {
return nil, false, nil
}
return nil, false, missingKey(idx)

Some files were not shown because too many files have changed in this diff Show More