Skip to content

Commit 696a687

Browse files
CEL Dev Teamcopybara-github
CEL Dev Team
authored andcommitted
Add CEL enum support
Introduces the `EnumValue`, which behaves like an `IntValue`, but keeps track of the enum name, so that it can be printed using `string.format()`. PiperOrigin-RevId: 717454914
1 parent 9a8b79d commit 696a687

17 files changed

+1910
-34
lines changed

bazel/deps.bzl

+16-6
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ def cel_spec_deps():
150150
urls = ["https://github.com/google/cel-spec/archive/" + CEL_SPEC_GIT_SHA + ".zip"],
151151
)
152152

153+
_ICU4C_VERSION_MAJOR = "76"
154+
_ICU4C_VERSION_MINOR = "1"
153155
_ICU4C_BUILD = """
154156
load("@rules_foreign_cc//foreign_cc:configure.bzl", "configure_make")
155157
@@ -161,9 +163,9 @@ filegroup(
161163
162164
config_setting(
163165
name = "dbg",
164-
values = {
166+
values = {{
165167
"compilation_mode": "dbg",
166-
},
168+
}},
167169
visibility = ["//visibility:private"],
168170
)
169171
@@ -178,16 +180,24 @@ configure_make(
178180
"--disable-icuio",
179181
"--disable-layoutex",
180182
"--disable-icu-config",
181-
] + select({
183+
] + select({{
182184
":dbg": ["--enable-debug"],
183185
"//conditions:default": [],
184-
}),
186+
}}),
185187
lib_source = ":all",
186188
out_shared_libs = [
187189
"libicudata.so",
190+
"libicudata.so.{version_major}",
191+
"libicudata.so.{version_major}.{version_minor}",
188192
"libicui18n.so",
193+
"libicui18n.so.{version_major}",
194+
"libicui18n.so.{version_major}.{version_minor}",
189195
"libicutu.so",
196+
"libicutu.so.{version_major}",
197+
"libicutu.so.{version_major}.{version_minor}",
190198
"libicuuc.so",
199+
"libicuuc.so.{version_major}",
200+
"libicuuc.so.{version_major}.{version_minor}",
191201
],
192202
out_static_libs = [
193203
"libicudata.a",
@@ -198,7 +208,7 @@ configure_make(
198208
args = ["-j 8"],
199209
visibility = ["//visibility:public"],
200210
)
201-
"""
211+
""".format(version_major = _ICU4C_VERSION_MAJOR, version_minor = _ICU4C_VERSION_MINOR)
202212

203213
def cel_cpp_extensions_deps():
204214
http_archive(
@@ -210,7 +220,7 @@ def cel_cpp_extensions_deps():
210220
http_archive(
211221
name = "icu4c",
212222
sha256 = "dfacb46bfe4747410472ce3e1144bf28a102feeaa4e3875bac9b4c6cf30f4f3e",
213-
url = "https://github.com/unicode-org/icu/releases/download/release-76-1/icu4c-76_1-src.tgz",
223+
url = "https://github.com/unicode-org/icu/releases/download/release-{version_major}-{version_minor}/icu4c-{version_major}_{version_minor}-src.tgz".format(version_major = _ICU4C_VERSION_MAJOR, version_minor = _ICU4C_VERSION_MINOR),
214224
strip_prefix = "icu",
215225
patch_cmds = [
216226
"rm -f source/common/BUILD.bazel",

common/BUILD

-1
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,6 @@ cc_library(
637637
"//internal:message_equality",
638638
"//internal:number",
639639
"//internal:protobuf_runtime_version",
640-
"//internal:serialize",
641640
"//internal:status_macros",
642641
"//internal:strings",
643642
"//internal:time",

common/value.cc

+41-13
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
namespace cel {
6464
namespace {
6565

66-
static constexpr std::array<ValueKind, 25> kValueToKindArray = {
66+
static constexpr std::array kValueToKindArray = {
6767
ValueKind::kError, ValueKind::kBool, ValueKind::kBytes,
6868
ValueKind::kDouble, ValueKind::kDuration, ValueKind::kError,
6969
ValueKind::kInt, ValueKind::kList, ValueKind::kList,
@@ -72,7 +72,7 @@ static constexpr std::array<ValueKind, 25> kValueToKindArray = {
7272
ValueKind::kNull, ValueKind::kOpaque, ValueKind::kString,
7373
ValueKind::kStruct, ValueKind::kStruct, ValueKind::kStruct,
7474
ValueKind::kTimestamp, ValueKind::kType, ValueKind::kUint,
75-
ValueKind::kUnknown};
75+
ValueKind::kUnknown, ValueKind::kInt};
7676

7777
static_assert(kValueToKindArray.size() ==
7878
absl::variant_size<common_internal::ValueVariant>(),
@@ -750,17 +750,20 @@ namespace {
750750
Value NonNullEnumValue(
751751
absl::Nonnull<const google::protobuf::EnumValueDescriptor*> value) {
752752
ABSL_DCHECK(value != nullptr);
753-
return IntValue(value->number());
753+
return EnumValue(value);
754754
}
755755

756756
Value NonNullEnumValue(absl::Nonnull<const google::protobuf::EnumDescriptor*> type,
757757
int32_t number) {
758758
ABSL_DCHECK(type != nullptr);
759-
if (type->is_closed()) {
760-
if (ABSL_PREDICT_FALSE(type->FindValueByNumber(number) == nullptr)) {
761-
return ErrorValue(absl::InvalidArgumentError(absl::StrCat(
762-
"closed enum has no such value: ", type->full_name(), ".", number)));
763-
}
759+
const google::protobuf::EnumValueDescriptor* enum_value =
760+
type->FindValueByNumber(number);
761+
if (type->is_closed() && ABSL_PREDICT_FALSE(enum_value == nullptr)) {
762+
return ErrorValue(absl::InvalidArgumentError(absl::StrCat(
763+
"closed enum has no such value: ", type->full_name(), ".", number)));
764+
}
765+
if (enum_value != nullptr) {
766+
return EnumValue(enum_value);
764767
}
765768
return IntValue(number);
766769
}
@@ -1943,6 +1946,18 @@ absl::optional<IntValue> Value::AsInt() const {
19431946
alternative != nullptr) {
19441947
return *alternative;
19451948
}
1949+
if (const auto* alternative = absl::get_if<EnumValue>(&variant_);
1950+
alternative != nullptr) {
1951+
return IntValue(alternative->NativeValue());
1952+
}
1953+
return absl::nullopt;
1954+
}
1955+
1956+
absl::optional<EnumValue> Value::AsEnum() const {
1957+
if (const auto* alternative = absl::get_if<EnumValue>(&variant_);
1958+
alternative != nullptr) {
1959+
return *alternative;
1960+
}
19461961
return absl::nullopt;
19471962
}
19481963

@@ -2350,18 +2365,31 @@ ErrorValue Value::GetError() && {
23502365
return absl::get<ErrorValue>(std::move(variant_));
23512366
}
23522367

2353-
IntValue Value::GetInt() const {
2354-
ABSL_DCHECK(IsInt()) << *this;
2355-
return absl::get<IntValue>(variant_);
2356-
}
2357-
23582368
#ifdef ABSL_HAVE_EXCEPTIONS
23592369
#define CEL_VALUE_THROW_BAD_VARIANT_ACCESS() throw absl::bad_variant_access()
23602370
#else
23612371
#define CEL_VALUE_THROW_BAD_VARIANT_ACCESS() \
23622372
ABSL_LOG(FATAL) << absl::bad_variant_access().what() /* Crash OK */
23632373
#endif
23642374

2375+
IntValue Value::GetInt() const {
2376+
ABSL_DCHECK(IsInt()) << *this;
2377+
if (const auto* alternative = absl::get_if<IntValue>(&variant_);
2378+
alternative != nullptr) {
2379+
return *alternative;
2380+
}
2381+
if (const auto* alternative = absl::get_if<EnumValue>(&variant_);
2382+
alternative != nullptr) {
2383+
return IntValue(alternative->NativeValue());
2384+
}
2385+
CEL_VALUE_THROW_BAD_VARIANT_ACCESS();
2386+
}
2387+
2388+
EnumValue Value::GetEnum() const {
2389+
ABSL_DCHECK(IsEnum()) << *this;
2390+
return absl::get<EnumValue>(variant_);
2391+
}
2392+
23652393
ListValue Value::GetList() const& {
23662394
ABSL_DCHECK(IsList()) << *this;
23672395
if (const auto* alternative =

common/value.h

+43-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,13 @@ class Value final {
501501
bool IsError() const { return absl::holds_alternative<ErrorValue>(variant_); }
502502

503503
// Returns `true` if this value is an instance of an int value.
504-
bool IsInt() const { return absl::holds_alternative<IntValue>(variant_); }
504+
bool IsInt() const {
505+
return absl::holds_alternative<IntValue>(variant_) ||
506+
absl::holds_alternative<EnumValue>(variant_);
507+
}
508+
509+
// Returns `true` if this value is an instance of an enum value.
510+
bool IsEnum() const { return absl::holds_alternative<EnumValue>(variant_); }
505511

506512
// Returns `true` if this value is an instance of a list value.
507513
bool IsList() const {
@@ -671,6 +677,13 @@ class Value final {
671677
return IsInt();
672678
}
673679

680+
// Convenience method for use with template metaprogramming. See
681+
// `IsEnum()`.
682+
template <typename T>
683+
std::enable_if_t<std::is_same_v<EnumValue, T>, bool> Is() const {
684+
return IsEnum();
685+
}
686+
674687
// Convenience method for use with template metaprogramming. See
675688
// `IsList()`.
676689
template <typename T>
@@ -856,6 +869,11 @@ class Value final {
856869
// int value. Otherwise an empty optional is returned.
857870
absl::optional<IntValue> AsInt() const;
858871

872+
// Performs a checked cast from a value to an enum value,
873+
// returning a non-empty optional with either a value or reference to the
874+
// enum value. Otherwise an empty optional is returned.
875+
absl::optional<EnumValue> AsEnum() const;
876+
859877
// Performs a checked cast from a value to a list value,
860878
// returning a non-empty optional with either a value or reference to the
861879
// list value. Otherwise an empty optional is returned.
@@ -1791,6 +1809,11 @@ class Value final {
17911809
// false, calling this method is undefined behavior.
17921810
IntValue GetInt() const;
17931811

1812+
// Performs an unchecked cast from a value to an int value. In
1813+
// debug builds a best effort is made to crash. If `IsInt()` would return
1814+
// false, calling this method is undefined behavior.
1815+
EnumValue GetEnum() const;
1816+
17941817
// Performs an unchecked cast from a value to a list value. In
17951818
// debug builds a best effort is made to crash. If `IsList()` would return
17961819
// false, calling this method is undefined behavior.
@@ -2104,6 +2127,25 @@ class Value final {
21042127
return GetInt();
21052128
}
21062129

2130+
// Convenience method for use with template metaprogramming. See
2131+
// `GetEnum()`.
2132+
template <typename T>
2133+
std::enable_if_t<std::is_same_v<EnumValue, T>, EnumValue> Get() & {
2134+
return GetEnum();
2135+
}
2136+
template <typename T>
2137+
std::enable_if_t<std::is_same_v<EnumValue, T>, EnumValue> Get() const& {
2138+
return GetEnum();
2139+
}
2140+
template <typename T>
2141+
std::enable_if_t<std::is_same_v<EnumValue, T>, EnumValue> Get() && {
2142+
return GetEnum();
2143+
}
2144+
template <typename T>
2145+
std::enable_if_t<std::is_same_v<EnumValue, T>, EnumValue> Get() const&& {
2146+
return GetEnum();
2147+
}
2148+
21072149
// Convenience method for use with template metaprogramming. See
21082150
// `GetList()`.
21092151
template <typename T>

common/values/enum_value.cc

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/protobuf/wrappers.pb.h"
16+
#include "absl/status/statusor.h"
17+
#include "common/value.h"
18+
19+
namespace cel {
20+
21+
absl::StatusOr<Value> EnumValue::Equal(ValueManager& value_manager,
22+
const Value& other) const {
23+
return IntValue(NativeValue()).Equal(value_manager, other);
24+
}
25+
26+
} // namespace cel

0 commit comments

Comments
 (0)