Skip to content

Commit

Permalink
internal change
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 574589703
  • Loading branch information
jnthntatum authored and copybara-github committed Oct 18, 2023
1 parent 11d6651 commit 2cdfd63
Show file tree
Hide file tree
Showing 9 changed files with 696 additions and 3 deletions.
3 changes: 3 additions & 0 deletions base/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,10 @@ cc_library(
":function",
":function_descriptor",
":handle",
":kind",
"//base/internal:function_adapter",
"//internal:status_macros",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/log:die_if_null",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
Expand All @@ -356,6 +358,7 @@ cc_test(
"//internal:testing",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
)
Expand Down
132 changes: 131 additions & 1 deletion base/function_adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@

#include <functional>
#include <memory>
#include <vector>

#include "absl/functional/bind_front.h"
#include "absl/log/die_if_null.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "base/function.h"
#include "base/function_descriptor.h"
#include "base/handle.h"
#include "base/internal/function_adapter.h"
#include "base/kind.h"
#include "base/value.h"
#include "internal/status_macros.h"

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

static const T& ToArg(AssignableType v) { return *ABSL_DIE_IF_NULL(v); }
static std::reference_wrapper<const T> ToArg(AssignableType v) {
return *ABSL_DIE_IF_NULL(v); // Crash OK
}
};

template <typename... Args>
struct KindAdderImpl;

template <typename Arg, typename... Args>
struct KindAdderImpl<Arg, Args...> {
static void AddTo(std::vector<cel::Kind>& args) {
args.push_back(AdaptedKind<Arg>());
KindAdderImpl<Args...>::AddTo(args);
}
};

template <>
struct KindAdderImpl<> {
static void AddTo(std::vector<cel::Kind>& args) {}
};

template <typename... Args>
struct KindAdder {
static std::vector<cel::Kind> Kinds() {
std::vector<cel::Kind> args;
KindAdderImpl<Args...>::AddTo(args);
return args;
}
};

template <typename T>
struct ApplyReturnType {
using type = absl::StatusOr<T>;
};

template <typename T>
struct ApplyReturnType<absl::StatusOr<T>> {
using type = absl::StatusOr<T>;
};

template <int N, typename Arg, typename... Args>
struct IndexerImpl {
using type = typename IndexerImpl<N - 1, Args...>::type;
};

template <typename Arg, typename... Args>
struct IndexerImpl<0, Arg, Args...> {
using type = Arg;
};

template <int N, typename... Args>
struct Indexer {
static_assert(N < sizeof...(Args) && N >= 0);
using type = typename IndexerImpl<N, Args...>::type;
};

template <int N, typename... Args>
struct ApplyHelper {
template <typename T, typename Op>
static typename ApplyReturnType<T>::type Apply(
Op&& op, absl::Span<const Handle<Value>> input) {
constexpr int idx = sizeof...(Args) - N;
using Arg = typename Indexer<idx, Args...>::type;
using ArgTraits = internal::AdaptedTypeTraits<Arg>;
typename ArgTraits::AssignableType arg_i;
CEL_RETURN_IF_ERROR(internal::HandleToAdaptedVisitor{input[idx]}(&arg_i));

return ApplyHelper<N - 1, Args...>::template Apply<T>(
absl::bind_front(std::forward<Op>(op), ArgTraits::ToArg(arg_i)), input);
}
};

template <typename... Args>
struct ApplyHelper<0, Args...> {
template <typename T, typename Op>
static typename ApplyReturnType<T>::type Apply(
Op&& op, absl::Span<const Handle<Value>> input) {
return op();
}
};

} // namespace internal
Expand Down Expand Up @@ -223,6 +305,54 @@ class UnaryFunctionAdapter {
};
};

// Generic adapter class for generating CEL extension functions from an
// n-argument function. Prefer using the Binary and Unary versions. They are
// simpler and cover most use cases.
//
// See documentation for Binary Function adapter for general recommendations.
template <typename T, typename... Args>
class VariadicFunctionAdapter {
public:
using FunctionType = std::function<T(ValueFactory&, Args...)>;

static std::unique_ptr<cel::Function> WrapFunction(FunctionType fn) {
return std::make_unique<VariadicFunctionImpl>(std::move(fn));
}

static FunctionDescriptor CreateDescriptor(absl::string_view name,
bool receiver_style,
bool is_strict = true) {
return FunctionDescriptor(name, receiver_style,
internal::KindAdder<Args...>::Kinds(), is_strict);
}

private:
class VariadicFunctionImpl : public cel::Function {
public:
explicit VariadicFunctionImpl(FunctionType fn) : fn_(std::move(fn)) {}

absl::StatusOr<Handle<Value>> Invoke(
const FunctionEvaluationContext& context,
absl::Span<const Handle<Value>> args) const override {
if (args.size() != sizeof...(Args)) {
return absl::InvalidArgumentError(
absl::StrCat("unexpected number of arguments for variadic(",
sizeof...(Args), ") function"));
}

CEL_ASSIGN_OR_RETURN(
T result,
(internal::ApplyHelper<sizeof...(Args), Args...>::template Apply<T>(
absl::bind_front(fn_, std::ref(context.value_factory())), args)));
return internal::AdaptedToHandleVisitor{context.value_factory()}(
std::move(result));
}

private:
FunctionType fn_;
};
};

} // namespace cel

#endif // THIRD_PARTY_CEL_CPP_BASE_FUNCTION_ADAPTER_H_
103 changes: 103 additions & 0 deletions base/function_adapter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,22 @@

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
#include "base/function.h"
#include "base/function_descriptor.h"
#include "base/handle.h"
#include "base/kind.h"
#include "base/memory.h"
#include "base/type_factory.h"
#include "base/type_manager.h"
#include "base/type_provider.h"
#include "base/value.h"
#include "base/value_factory.h"
#include "base/values/bool_value.h"
#include "base/values/bytes_value.h"
#include "base/values/double_value.h"
#include "base/values/duration_value.h"
#include "base/values/int_value.h"
#include "base/values/timestamp_value.h"
#include "base/values/uint_value.h"
Expand All @@ -42,6 +46,7 @@ namespace {

using testing::ElementsAre;
using testing::HasSubstr;
using testing::IsEmpty;
using cel::internal::StatusIs;

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

TEST_F(FunctionAdapterTest, VariadicFunctionAdapterCreateDescriptor0Args) {
FunctionDescriptor desc =
VariadicFunctionAdapter<absl::StatusOr<Handle<Value>>>::CreateDescriptor(
"ZeroArgs", false);

EXPECT_EQ(desc.name(), "ZeroArgs");
EXPECT_TRUE(desc.is_strict());
EXPECT_FALSE(desc.receiver_style());
EXPECT_THAT(desc.types(), IsEmpty());
}

TEST_F(FunctionAdapterTest, VariadicFunctionAdapterWrapFunction0Args) {
std::unique_ptr<Function> fn =
VariadicFunctionAdapter<absl::StatusOr<Handle<Value>>>::WrapFunction(
[](ValueFactory& value_factory) {
return value_factory.CreateStringValue("abc");
});

ASSERT_OK_AND_ASSIGN(auto result, fn->Invoke(test_context(), {}));
ASSERT_TRUE(result->Is<StringValue>());
EXPECT_EQ(result.As<StringValue>()->ToString(), "abc");
}

TEST_F(FunctionAdapterTest, VariadicFunctionAdapterCreateDescriptor3Args) {
FunctionDescriptor desc = VariadicFunctionAdapter<
absl::StatusOr<Handle<Value>>, int64_t, bool,
const StringValue&>::CreateDescriptor("MyFormatter", false);

EXPECT_EQ(desc.name(), "MyFormatter");
EXPECT_TRUE(desc.is_strict());
EXPECT_FALSE(desc.receiver_style());
EXPECT_THAT(desc.types(),
ElementsAre(Kind::kInt64, Kind::kBool, Kind::kString));
}

TEST_F(FunctionAdapterTest, VariadicFunctionAdapterWrapFunction3Args) {
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
absl::StatusOr<Handle<Value>>, int64_t, bool,
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
int64_t int_val, bool bool_val,
const StringValue& string_val)
-> absl::StatusOr<Handle<Value>> {
return value_factory.CreateStringValue(
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
string_val.ToString()));
});

std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
value_factory().CreateBoolValue(false)};
ASSERT_OK_AND_ASSIGN(args.emplace_back(),
value_factory().CreateStringValue("abcd"));
ASSERT_OK_AND_ASSIGN(auto result, fn->Invoke(test_context(), args));
ASSERT_TRUE(result->Is<StringValue>());
EXPECT_EQ(result.As<StringValue>()->ToString(), "42_false_abcd");
}

TEST_F(FunctionAdapterTest,
VariadicFunctionAdapterWrapFunction3ArgsBadArgType) {
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
absl::StatusOr<Handle<Value>>, int64_t, bool,
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
int64_t int_val, bool bool_val,
const StringValue& string_val)
-> absl::StatusOr<Handle<Value>> {
return value_factory.CreateStringValue(
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
string_val.ToString()));
});

std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
value_factory().CreateBoolValue(false)};
ASSERT_OK_AND_ASSIGN(args.emplace_back(),
value_factory().CreateTimestampValue(absl::UnixEpoch()));
EXPECT_THAT(fn->Invoke(test_context(), args),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("expected string value")));
}

TEST_F(FunctionAdapterTest,
VariadicFunctionAdapterWrapFunction3ArgsBadArgCount) {
std::unique_ptr<Function> fn = VariadicFunctionAdapter<
absl::StatusOr<Handle<Value>>, int64_t, bool,
const StringValue&>::WrapFunction([](ValueFactory& value_factory,
int64_t int_val, bool bool_val,
const StringValue& string_val)
-> absl::StatusOr<Handle<Value>> {
return value_factory.CreateStringValue(
absl::StrCat(int_val, "_", (bool_val ? "true" : "false"), "_",
string_val.ToString()));
});

std::vector<Handle<Value>> args{value_factory().CreateIntValue(42),
value_factory().CreateBoolValue(false)};
EXPECT_THAT(fn->Invoke(test_context(), args),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("unexpected number of arguments")));
}

} // namespace
} // namespace cel
37 changes: 37 additions & 0 deletions extensions/protobuf/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,40 @@ cc_test(
"@com_google_protobuf//:protobuf",
],
)

cc_library(
name = "bind_proto_to_activation",
srcs = ["bind_proto_to_activation.cc"],
hdrs = ["bind_proto_to_activation.h"],
deps = [
":data",
"//base:data",
"//base:handle",
"//internal:status_macros",
"//runtime:activation",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
],
)

cc_test(
name = "bind_proto_to_activation_test",
srcs = ["bind_proto_to_activation_test.cc"],
deps = [
":bind_proto_to_activation",
":data",
":memory_manager",
"//base:data",
"//base:handle",
"//base:memory",
"//internal:testing",
"//runtime:activation",
"//runtime:managed_value_factory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/types:optional",
"@com_google_cel_spec//proto/test/v1/proto2:test_all_types_cc_proto",
"@com_google_protobuf//:protobuf",
],
)
Loading

0 comments on commit 2cdfd63

Please sign in to comment.