Skip to content

Commit 2cdfd63

Browse files
jnthntatumcopybara-github
authored andcommitted
internal change
PiperOrigin-RevId: 574589703
1 parent 11d6651 commit 2cdfd63

9 files changed

+696
-3
lines changed

base/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,10 @@ cc_library(
332332
":function",
333333
":function_descriptor",
334334
":handle",
335+
":kind",
335336
"//base/internal:function_adapter",
336337
"//internal:status_macros",
338+
"@com_google_absl//absl/functional:bind_front",
337339
"@com_google_absl//absl/log:die_if_null",
338340
"@com_google_absl//absl/status",
339341
"@com_google_absl//absl/status:statusor",
@@ -356,6 +358,7 @@ cc_test(
356358
"//internal:testing",
357359
"@com_google_absl//absl/status",
358360
"@com_google_absl//absl/status:statusor",
361+
"@com_google_absl//absl/strings",
359362
"@com_google_absl//absl/time",
360363
],
361364
)

base/function_adapter.h

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,20 @@
2222

2323
#include <functional>
2424
#include <memory>
25+
#include <vector>
2526

27+
#include "absl/functional/bind_front.h"
2628
#include "absl/log/die_if_null.h"
2729
#include "absl/status/status.h"
2830
#include "absl/status/statusor.h"
31+
#include "absl/strings/str_cat.h"
2932
#include "absl/strings/string_view.h"
3033
#include "absl/types/span.h"
3134
#include "base/function.h"
3235
#include "base/function_descriptor.h"
3336
#include "base/handle.h"
3437
#include "base/internal/function_adapter.h"
38+
#include "base/kind.h"
3539
#include "base/value.h"
3640
#include "internal/status_macros.h"
3741

@@ -51,7 +55,85 @@ template <typename T>
5155
struct AdaptedTypeTraits<const T&> {
5256
using AssignableType = const T*;
5357

54-
static const T& ToArg(AssignableType v) { return *ABSL_DIE_IF_NULL(v); }
58+
static std::reference_wrapper<const T> ToArg(AssignableType v) {
59+
return *ABSL_DIE_IF_NULL(v); // Crash OK
60+
}
61+
};
62+
63+
template <typename... Args>
64+
struct KindAdderImpl;
65+
66+
template <typename Arg, typename... Args>
67+
struct KindAdderImpl<Arg, Args...> {
68+
static void AddTo(std::vector<cel::Kind>& args) {
69+
args.push_back(AdaptedKind<Arg>());
70+
KindAdderImpl<Args...>::AddTo(args);
71+
}
72+
};
73+
74+
template <>
75+
struct KindAdderImpl<> {
76+
static void AddTo(std::vector<cel::Kind>& args) {}
77+
};
78+
79+
template <typename... Args>
80+
struct KindAdder {
81+
static std::vector<cel::Kind> Kinds() {
82+
std::vector<cel::Kind> args;
83+
KindAdderImpl<Args...>::AddTo(args);
84+
return args;
85+
}
86+
};
87+
88+
template <typename T>
89+
struct ApplyReturnType {
90+
using type = absl::StatusOr<T>;
91+
};
92+
93+
template <typename T>
94+
struct ApplyReturnType<absl::StatusOr<T>> {
95+
using type = absl::StatusOr<T>;
96+
};
97+
98+
template <int N, typename Arg, typename... Args>
99+
struct IndexerImpl {
100+
using type = typename IndexerImpl<N - 1, Args...>::type;
101+
};
102+
103+
template <typename Arg, typename... Args>
104+
struct IndexerImpl<0, Arg, Args...> {
105+
using type = Arg;
106+
};
107+
108+
template <int N, typename... Args>
109+
struct Indexer {
110+
static_assert(N < sizeof...(Args) && N >= 0);
111+
using type = typename IndexerImpl<N, Args...>::type;
112+
};
113+
114+
template <int N, typename... Args>
115+
struct ApplyHelper {
116+
template <typename T, typename Op>
117+
static typename ApplyReturnType<T>::type Apply(
118+
Op&& op, absl::Span<const Handle<Value>> input) {
119+
constexpr int idx = sizeof...(Args) - N;
120+
using Arg = typename Indexer<idx, Args...>::type;
121+
using ArgTraits = internal::AdaptedTypeTraits<Arg>;
122+
typename ArgTraits::AssignableType arg_i;
123+
CEL_RETURN_IF_ERROR(internal::HandleToAdaptedVisitor{input[idx]}(&arg_i));
124+
125+
return ApplyHelper<N - 1, Args...>::template Apply<T>(
126+
absl::bind_front(std::forward<Op>(op), ArgTraits::ToArg(arg_i)), input);
127+
}
128+
};
129+
130+
template <typename... Args>
131+
struct ApplyHelper<0, Args...> {
132+
template <typename T, typename Op>
133+
static typename ApplyReturnType<T>::type Apply(
134+
Op&& op, absl::Span<const Handle<Value>> input) {
135+
return op();
136+
}
55137
};
56138

57139
} // namespace internal
@@ -223,6 +305,54 @@ class UnaryFunctionAdapter {
223305
};
224306
};
225307

308+
// Generic adapter class for generating CEL extension functions from an
309+
// n-argument function. Prefer using the Binary and Unary versions. They are
310+
// simpler and cover most use cases.
311+
//
312+
// See documentation for Binary Function adapter for general recommendations.
313+
template <typename T, typename... Args>
314+
class VariadicFunctionAdapter {
315+
public:
316+
using FunctionType = std::function<T(ValueFactory&, Args...)>;
317+
318+
static std::unique_ptr<cel::Function> WrapFunction(FunctionType fn) {
319+
return std::make_unique<VariadicFunctionImpl>(std::move(fn));
320+
}
321+
322+
static FunctionDescriptor CreateDescriptor(absl::string_view name,
323+
bool receiver_style,
324+
bool is_strict = true) {
325+
return FunctionDescriptor(name, receiver_style,
326+
internal::KindAdder<Args...>::Kinds(), is_strict);
327+
}
328+
329+
private:
330+
class VariadicFunctionImpl : public cel::Function {
331+
public:
332+
explicit VariadicFunctionImpl(FunctionType fn) : fn_(std::move(fn)) {}
333+
334+
absl::StatusOr<Handle<Value>> Invoke(
335+
const FunctionEvaluationContext& context,
336+
absl::Span<const Handle<Value>> args) const override {
337+
if (args.size() != sizeof...(Args)) {
338+
return absl::InvalidArgumentError(
339+
absl::StrCat("unexpected number of arguments for variadic(",
340+
sizeof...(Args), ") function"));
341+
}
342+
343+
CEL_ASSIGN_OR_RETURN(
344+
T result,
345+
(internal::ApplyHelper<sizeof...(Args), Args...>::template Apply<T>(
346+
absl::bind_front(fn_, std::ref(context.value_factory())), args)));
347+
return internal::AdaptedToHandleVisitor{context.value_factory()}(
348+
std::move(result));
349+
}
350+
351+
private:
352+
FunctionType fn_;
353+
};
354+
};
355+
226356
} // namespace cel
227357

228358
#endif // THIRD_PARTY_CEL_CPP_BASE_FUNCTION_ADAPTER_H_

base/function_adapter_test.cc

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,22 @@
2020

2121
#include "absl/status/status.h"
2222
#include "absl/status/statusor.h"
23+
#include "absl/strings/str_cat.h"
2324
#include "absl/time/time.h"
2425
#include "base/function.h"
2526
#include "base/function_descriptor.h"
2627
#include "base/handle.h"
2728
#include "base/kind.h"
2829
#include "base/memory.h"
2930
#include "base/type_factory.h"
31+
#include "base/type_manager.h"
3032
#include "base/type_provider.h"
33+
#include "base/value.h"
3134
#include "base/value_factory.h"
3235
#include "base/values/bool_value.h"
3336
#include "base/values/bytes_value.h"
3437
#include "base/values/double_value.h"
38+
#include "base/values/duration_value.h"
3539
#include "base/values/int_value.h"
3640
#include "base/values/timestamp_value.h"
3741
#include "base/values/uint_value.h"
@@ -42,6 +46,7 @@ namespace {
4246

4347
using testing::ElementsAre;
4448
using testing::HasSubstr;
49+
using testing::IsEmpty;
4550
using cel::internal::StatusIs;
4651

4752
class FunctionAdapterTest : public ::testing::Test {
@@ -719,5 +724,103 @@ TEST_F(FunctionAdapterTest, BinaryFunctionAdapterCreateDescriptorNonStrict) {
719724
EXPECT_THAT(desc.types(), ElementsAre(Kind::kAny, Kind::kAny));
720725
}
721726

727+
TEST_F(FunctionAdapterTest, VariadicFunctionAdapterCreateDescriptor0Args) {
728+
FunctionDescriptor desc =
729+
VariadicFunctionAdapter<absl::StatusOr<Handle<Value>>>::CreateDescriptor(
730+
"ZeroArgs", false);
731+
732+
EXPECT_EQ(desc.name(), "ZeroArgs");
733+
EXPECT_TRUE(desc.is_strict());
734+
EXPECT_FALSE(desc.receiver_style());
735+
EXPECT_THAT(desc.types(), IsEmpty());
736+
}
737+
738+
TEST_F(FunctionAdapterTest, VariadicFunctionAdapterWrapFunction0Args) {
739+
std::unique_ptr<Function> fn =
740+
VariadicFunctionAdapter<absl::StatusOr<Handle<Value>>>::WrapFunction(
741+
[](ValueFactory& value_factory) {
742+
return value_factory.CreateStringValue("abc");
743+
});
744+
745+
ASSERT_OK_AND_ASSIGN(auto result, fn->Invoke(test_context(), {}));
746+
ASSERT_TRUE(result->Is<StringValue>());
747+
EXPECT_EQ(result.As<StringValue>()->ToString(), "abc");
748+
}
749+
750+
TEST_F(FunctionAdapterTest, VariadicFunctionAdapterCreateDescriptor3Args) {
751+
FunctionDescriptor desc = VariadicFunctionAdapter<
752+
absl::StatusOr<Handle<Value>>, int64_t, bool,
753+
const StringValue&>::CreateDescriptor("MyFormatter", false);
754+
755+
EXPECT_EQ(desc.name(), "MyFormatter");
756+
EXPECT_TRUE(desc.is_strict());
757+
EXPECT_FALSE(desc.receiver_style());
758+
EXPECT_THAT(desc.types(),
759+
ElementsAre(Kind::kInt64, Kind::kBool, Kind::kString));
760+
}
761+
762+
TEST_F(FunctionAdapterTest, VariadicFunctionAdapterWrapFunction3Args) {
763+
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
764+
absl::StatusOr<Handle<Value>>, int64_t, bool,
765+
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
766+
int64_t int_val, bool bool_val,
767+
const StringValue& string_val)
768+
-> absl::StatusOr<Handle<Value>> {
769+
return value_factory.CreateStringValue(
770+
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
771+
string_val.ToString()));
772+
});
773+
774+
std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
775+
value_factory().CreateBoolValue(false)};
776+
ASSERT_OK_AND_ASSIGN(args.emplace_back(),
777+
value_factory().CreateStringValue("abcd"));
778+
ASSERT_OK_AND_ASSIGN(auto result, fn->Invoke(test_context(), args));
779+
ASSERT_TRUE(result->Is<StringValue>());
780+
EXPECT_EQ(result.As<StringValue>()->ToString(), "42_false_abcd");
781+
}
782+
783+
TEST_F(FunctionAdapterTest,
784+
VariadicFunctionAdapterWrapFunction3ArgsBadArgType) {
785+
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
786+
absl::StatusOr<Handle<Value>>, int64_t, bool,
787+
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
788+
int64_t int_val, bool bool_val,
789+
const StringValue& string_val)
790+
-> absl::StatusOr<Handle<Value>> {
791+
return value_factory.CreateStringValue(
792+
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
793+
string_val.ToString()));
794+
});
795+
796+
std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
797+
value_factory().CreateBoolValue(false)};
798+
ASSERT_OK_AND_ASSIGN(args.emplace_back(),
799+
value_factory().CreateTimestampValue(absl::UnixEpoch()));
800+
EXPECT_THAT(fn->Invoke(test_context(), args),
801+
StatusIs(absl::StatusCode::kInvalidArgument,
802+
HasSubstr("expected string value")));
803+
}
804+
805+
TEST_F(FunctionAdapterTest,
806+
VariadicFunctionAdapterWrapFunction3ArgsBadArgCount) {
807+
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
808+
absl::StatusOr<Handle<Value>>, int64_t, bool,
809+
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
810+
int64_t int_val, bool bool_val,
811+
const StringValue& string_val)
812+
-> absl::StatusOr<Handle<Value>> {
813+
return value_factory.CreateStringValue(
814+
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
815+
string_val.ToString()));
816+
});
817+
818+
std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
819+
value_factory().CreateBoolValue(false)};
820+
EXPECT_THAT(fn->Invoke(test_context(), args),
821+
StatusIs(absl::StatusCode::kInvalidArgument,
822+
HasSubstr("unexpected number of arguments")));
823+
}
824+
722825
} // namespace
723826
} // namespace cel

extensions/protobuf/BUILD

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,40 @@ cc_test(
268268
"@com_google_protobuf//:protobuf",
269269
],
270270
)
271+
272+
cc_library(
273+
name = "bind_proto_to_activation",
274+
srcs = ["bind_proto_to_activation.cc"],
275+
hdrs = ["bind_proto_to_activation.h"],
276+
deps = [
277+
":data",
278+
"//base:data",
279+
"//base:handle",
280+
"//internal:status_macros",
281+
"//runtime:activation",
282+
"@com_google_absl//absl/status",
283+
"@com_google_absl//absl/status:statusor",
284+
"@com_google_absl//absl/strings",
285+
"@com_google_protobuf//:protobuf",
286+
],
287+
)
288+
289+
cc_test(
290+
name = "bind_proto_to_activation_test",
291+
srcs = ["bind_proto_to_activation_test.cc"],
292+
deps = [
293+
":bind_proto_to_activation",
294+
":data",
295+
":memory_manager",
296+
"//base:data",
297+
"//base:handle",
298+
"//base:memory",
299+
"//internal:testing",
300+
"//runtime:activation",
301+
"//runtime:managed_value_factory",
302+
"@com_google_absl//absl/status",
303+
"@com_google_absl//absl/types:optional",
304+
"@com_google_cel_spec//proto/test/v1/proto2:test_all_types_cc_proto",
305+
"@com_google_protobuf//:protobuf",
306+
],
307+
)

0 commit comments

Comments
 (0)