Skip to content

Commit 198a614

Browse files
jckingcopybara-github
authored andcommitted
Add utility to clone CelValue onto the same or different google::protobuf::Arena
PiperOrigin-RevId: 986753915
1 parent 14fad34 commit 198a614

3 files changed

Lines changed: 227 additions & 0 deletions

File tree

‎eval/public/BUILD‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,28 @@ cc_library(
114114
],
115115
)
116116

117+
cc_library(
118+
name = "cel_value_clone",
119+
srcs = ["cel_value_clone.cc"],
120+
hdrs = ["cel_value_clone.h"],
121+
deps = [
122+
":cel_value",
123+
":message_wrapper",
124+
":unknown_set",
125+
"//eval/public/containers:container_backed_list_impl",
126+
"//eval/public/containers:container_backed_map_impl",
127+
"//internal:status_macros",
128+
"@com_google_absl//absl/log:absl_check",
129+
"@com_google_absl//absl/status",
130+
"@com_google_absl//absl/status:statusor",
131+
"@com_google_absl//absl/strings",
132+
"@com_google_absl//absl/strings:cord",
133+
"@com_google_absl//absl/time",
134+
"@com_google_absl//absl/types:optional",
135+
"@com_google_protobuf//:protobuf",
136+
],
137+
)
138+
117139
cc_library(
118140
name = "cel_attribute",
119141
srcs = [

‎eval/public/cel_value_clone.cc‎

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "eval/public/cel_value_clone.h"
18+
19+
#include <cstdint>
20+
#include <string>
21+
#include <utility>
22+
#include <vector>
23+
24+
#include "absl/log/absl_check.h"
25+
#include "absl/status/status.h"
26+
#include "absl/status/statusor.h"
27+
#include "absl/strings/cord.h"
28+
#include "absl/strings/str_cat.h"
29+
#include "absl/time/time.h"
30+
#include "absl/types/optional.h"
31+
#include "eval/public/cel_value.h"
32+
#include "eval/public/containers/container_backed_list_impl.h"
33+
#include "eval/public/containers/container_backed_map_impl.h"
34+
#include "eval/public/message_wrapper.h"
35+
#include "eval/public/unknown_set.h"
36+
#include "internal/status_macros.h"
37+
#include "google/protobuf/arena.h"
38+
39+
namespace google::api::expr::runtime {
40+
41+
namespace {
42+
43+
struct CloneVisitor {
44+
google::protobuf::Arena* const arena;
45+
46+
absl::StatusOr<CelValue> operator()(bool arg) {
47+
return CelValue::CreateBool(arg);
48+
}
49+
absl::StatusOr<CelValue> operator()(int64_t arg) {
50+
return CelValue::CreateInt64(arg);
51+
}
52+
absl::StatusOr<CelValue> operator()(uint64_t arg) {
53+
return CelValue::CreateUint64(arg);
54+
}
55+
absl::StatusOr<CelValue> operator()(double arg) {
56+
return CelValue::CreateDouble(arg);
57+
}
58+
absl::StatusOr<CelValue> operator()(CelValue::NullType) {
59+
return CelValue::CreateNull();
60+
}
61+
62+
absl::StatusOr<CelValue> operator()(CelValue::StringHolder arg) {
63+
if (arg.value().empty()) {
64+
return CelValue::CreateStringView("");
65+
}
66+
return CelValue::CreateString(CelValue::StringHolder(
67+
google::protobuf::Arena::Create<std::string>(arena, arg.value())));
68+
}
69+
70+
absl::StatusOr<CelValue> operator()(CelValue::BytesHolder arg) {
71+
if (arg.value().empty()) {
72+
return CelValue::CreateBytesView("");
73+
}
74+
return CelValue::CreateBytes(CelValue::BytesHolder(
75+
google::protobuf::Arena::Create<std::string>(arena, arg.value())));
76+
}
77+
78+
absl::StatusOr<CelValue> operator()(const MessageWrapper& arg) {
79+
if (arg.HasFullProto()) {
80+
google::protobuf::Message* dup =
81+
static_cast<const google::protobuf::Message*>(arg.message_ptr())->New(arena);
82+
dup->CopyFrom(*static_cast<const google::protobuf::Message*>(arg.message_ptr()));
83+
return CelValue::CreateMessageWrapper(
84+
MessageWrapper(dup, arg.legacy_type_info()));
85+
}
86+
google::protobuf::MessageLite* dup = arg.message_ptr()->New(arena);
87+
absl::Cord serialized;
88+
if (!arg.message_ptr()->SerializePartialToCord(&serialized)) {
89+
return absl::UnknownError(
90+
absl::StrCat("failed to serialize message: ", dup->GetTypeName()));
91+
}
92+
if (!dup->ParsePartialFromString(serialized)) {
93+
return absl::UnknownError(
94+
absl::StrCat("failed to parse message: ", dup->GetTypeName()));
95+
}
96+
return CelValue::CreateMessageWrapper(
97+
MessageWrapper(dup, arg.legacy_type_info()));
98+
}
99+
100+
absl::StatusOr<CelValue> operator()(absl::Duration arg) {
101+
return CelValue::CreateUncheckedDuration(arg);
102+
}
103+
104+
absl::StatusOr<CelValue> operator()(absl::Time arg) {
105+
return CelValue::CreateTimestamp(arg);
106+
}
107+
108+
absl::StatusOr<CelValue> operator()(const CelList* arg) {
109+
if (arg->empty()) {
110+
return CelValue::CreateList();
111+
}
112+
std::vector<CelValue> elements;
113+
elements.reserve(arg->size());
114+
for (int i = 0; i < arg->size(); i++) {
115+
CEL_ASSIGN_OR_RETURN(auto element,
116+
CelValueClone(arena, arg->Get(arena, i)));
117+
elements.push_back(element);
118+
}
119+
return CelValue::CreateList(google::protobuf::Arena::Create<ContainerBackedListImpl>(
120+
arena, std::move(elements)));
121+
}
122+
123+
absl::StatusOr<CelValue> operator()(const CelMap* arg) {
124+
if (arg->empty()) {
125+
return CelValue::CreateMap();
126+
}
127+
CEL_ASSIGN_OR_RETURN(auto keys, arg->ListKeys(arena));
128+
CelMapBuilder* builder = google::protobuf::Arena::Create<CelMapBuilder>(arena);
129+
for (int i = 0; i < keys->size(); ++i) {
130+
CelValue key = keys->Get(arena, i);
131+
absl::optional<CelValue> value = arg->Get(arena, key);
132+
if (!value.has_value()) {
133+
return absl::UnknownError(
134+
"CelMap::ListKeys returned key but CelMap::Get did not find the "
135+
"entry");
136+
}
137+
CEL_ASSIGN_OR_RETURN(auto key_dup, CelValueClone(arena, key));
138+
CEL_ASSIGN_OR_RETURN(auto value_dup, CelValueClone(arena, *value));
139+
CEL_RETURN_IF_ERROR(builder->Add(key_dup, value_dup));
140+
}
141+
return CelValue::CreateMap(builder);
142+
}
143+
144+
absl::StatusOr<CelValue> operator()(const UnknownSet* arg) {
145+
return CelValue::CreateUnknownSet(
146+
google::protobuf::Arena::Create<UnknownSet>(arena, *arg));
147+
}
148+
149+
absl::StatusOr<CelValue> operator()(CelValue::CelTypeHolder arg) {
150+
return CelValue::CreateCelType(CelValue::CelTypeHolder(
151+
google::protobuf::Arena::Create<std::string>(arena, arg.value())));
152+
}
153+
154+
absl::StatusOr<CelValue> operator()(const CelError* arg) {
155+
return CelValue::CreateError(google::protobuf::Arena::Create<CelError>(arena, *arg));
156+
}
157+
};
158+
159+
} // namespace
160+
161+
absl::StatusOr<CelValue> CelValueClone(google::protobuf::Arena* arena, CelValue in) {
162+
ABSL_DCHECK(arena != nullptr);
163+
return in.Visit<absl::StatusOr<CelValue>>(CloneVisitor{.arena = arena});
164+
}
165+
166+
} // namespace google::api::expr::runtime

‎eval/public/cel_value_clone.h‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef THIRD_PARTY_CEL_CPP_EVAL_PUBLIC_CEL_VALUE_CLONE_H_
18+
#define THIRD_PARTY_CEL_CPP_EVAL_PUBLIC_CEL_VALUE_CLONE_H_
19+
20+
#include "absl/status/statusor.h"
21+
#include "eval/public/cel_value.h"
22+
#include "google/protobuf/arena.h"
23+
24+
namespace google::api::expr::runtime {
25+
26+
// Clones a CelValue such that the resulting CelValue has a lifetime tied to the
27+
// given arena.
28+
absl::StatusOr<CelValue> CelValueClone(google::protobuf::Arena* arena, CelValue in);
29+
inline absl::StatusOr<CelValue> CelValueClone(google::protobuf::Arena* arena,
30+
absl::StatusOr<CelValue> in) {
31+
if (!in.ok()) {
32+
return in;
33+
}
34+
return CelValueClone(arena, *in);
35+
}
36+
37+
} // namespace google::api::expr::runtime
38+
39+
#endif // THIRD_PARTY_CEL_CPP_EVAL_PUBLIC_CEL_VALUE_CLONE_H_

0 commit comments

Comments
 (0)