hpb: Improve ergonomics by updating MakeCHandle to take in CMessageType*
PiperOrigin-RevId: 810532115
diff --git a/hpb/backend/upb/interop.h b/hpb/backend/upb/interop.h
index e4fb84d..8b54213 100644
--- a/hpb/backend/upb/interop.h
+++ b/hpb/backend/upb/interop.h
@@ -16,6 +16,7 @@
#include "hpb/internal/internal.h"
#include "hpb/ptr.h"
#include "upb/base/string_view.h"
+#include "upb/base/upcast.h"
#include "upb/mem/arena.h"
#include "upb/message/message.h"
#include "upb/mini_table/message.h"
@@ -85,11 +86,26 @@
* TODO: b/361596328 - revisit GetArena for CHandles
* TODO: b/362743843 - consider passing in MiniTable to ensure match
*/
+// REMARK: This overload will be deleted soon. Prefer the overloads that take in
+// the CMessageType or MiniTable.
template <typename T>
typename T::CProxy MakeCHandle(const upb_Message* msg, upb_Arena* arena) {
return internal::PrivateAccess::CProxy<T>(msg, arena);
}
+/* Creates a Handle from a const upb message.
+ *
+ * The supplied arena must outlive the hpb handle.
+ * All messages reachable from from the upb message must
+ * outlive the hpb handle.
+ */
+template <typename T>
+typename T::CProxy MakeCHandle(
+ const typename internal::AssociatedUpbTypes<T>::CMessageType* msg,
+ upb_Arena* arena) {
+ return internal::PrivateAccess::CProxy<T>(UPB_UPCAST(msg), arena);
+}
+
/**
* Creates a Handle to a mutable upb message.
*
@@ -97,11 +113,26 @@
* All messages reachable from from the upb message must
* outlive the hpb handle.
*/
+// REMARK: This overload will be deleted soon. Prefer the overloads that take in
+// the CMessageType or MiniTable.
template <typename T>
typename T::Proxy MakeHandle(upb_Message* msg, upb_Arena* arena) {
return typename T::Proxy(msg, arena);
}
+/* Creates a Handle from a mutable upb message.
+ *
+ * The supplied arena must outlive the hpb handle.
+ * All messages reachable from from the upb message must
+ * outlive the hpb handle.
+ */
+template <typename T>
+typename T::Proxy MakeHandle(
+ typename internal::AssociatedUpbTypes<T>::CMessageType* msg,
+ upb_Arena* arena) {
+ return internal::PrivateAccess::Proxy<T>(UPB_UPCAST(msg), arena);
+}
+
/**
* Creates a message in the given arena and returns a handle to it.
*
diff --git a/hpb/backend/upb/interop_test.cc b/hpb/backend/upb/interop_test.cc
index 5b72d5d..6fa67e6 100644
--- a/hpb/backend/upb/interop_test.cc
+++ b/hpb/backend/upb/interop_test.cc
@@ -32,5 +32,25 @@
EXPECT_EQ(model.int_value_with_default(), 123);
}
+TEST(CppGeneratedCode, CanCreateCProxyWithoutCasting) {
+ upb_Arena* arena = upb_Arena_New();
+ hpb_unittest_TestModel* msg = hpb_unittest_TestModel_new(arena);
+
+ hpb_unittest::protos::TestModel::CProxy const_handle =
+ hpb::interop::upb::MakeCHandle<TestModel>(msg, arena);
+ EXPECT_EQ(const_handle.value(), 0);
+ upb_Arena_Free(arena);
+}
+
+TEST(CppGeneratedCode, CanCreateProxyWithoutCasting) {
+ upb_Arena* arena = upb_Arena_New();
+ hpb_unittest_TestModel* msg = hpb_unittest_TestModel_new(arena);
+
+ hpb_unittest::protos::TestModel::Proxy handle =
+ hpb::interop::upb::MakeHandle<TestModel>(msg, arena);
+ EXPECT_EQ(handle.value(), 0);
+ upb_Arena_Free(arena);
+}
+
} // namespace
} // namespace hpb::testing
diff --git a/hpb/internal/internal.h b/hpb/internal/internal.h
index cff03ab..f4be198 100644
--- a/hpb/internal/internal.h
+++ b/hpb/internal/internal.h
@@ -58,6 +58,9 @@
}
};
+template <typename T>
+struct AssociatedUpbTypes;
+
} // namespace hpb::internal
#endif // GOOGLE_PROTOBUF_HPB_INTERNAL_INTERNAL_H__
diff --git a/hpb_generator/generator.cc b/hpb_generator/generator.cc
index d0f2e7d..15f463c 100644
--- a/hpb_generator/generator.cc
+++ b/hpb_generator/generator.cc
@@ -23,6 +23,7 @@
#include "hpb_generator/gen_utils.h"
#include "hpb_generator/names.h"
#include "google/protobuf/descriptor.h"
+#include "upb_generator/c/names.h"
namespace google {
namespace protobuf {
@@ -146,6 +147,31 @@
ctx.Emit("\n");
});
+ ctx.Emit("namespace hpb::internal {\n");
+ const std::vector<const google::protobuf::Descriptor*> messages_to_emit_helpers =
+ SortedMessages(file);
+ for (auto desc : messages_to_emit_helpers) {
+ if (desc->map_key() != nullptr) {
+ continue;
+ }
+ std::string outer_namespace =
+ absl::StrCat(NamespaceFromPackageName(file->package()), "::");
+ if (file->package().empty()) {
+ outer_namespace = "";
+ }
+ ctx.Emit({{"class_name", ClassName(desc)},
+ {"outer_namespace", outer_namespace},
+ {"c_api_msg_type",
+ upb::generator::CApiMessageType(desc->full_name())}},
+ R"cc(
+ template <>
+ struct AssociatedUpbTypes<$outer_namespace$$class_name$> {
+ using CMessageType = $c_api_msg_type$;
+ };
+ )cc");
+ }
+
+ ctx.Emit("} // namespace hpb::internal\n");
ctx.Emit(
"#include \"hpb/internal/os_macros_restore.inc\"\n");
ctx.Emit("\n#include \"upb/port/undef.inc\"\n\n");