Implement Maps for scalar types for the C++ kernel
This CL implements Maps for scalar types for the C++ runtime. It's orthogonal to cl/580453646. This CL is constrained by having to force template instantiation of proto2::Map<K, V>. Put differently, a Rust protobuf::Map<K, V> implementation needs to call 'extern "C"' functions with both key and value type in the function name (e.g. __pb_rust_Map_i32_f64_get()). We use macros to generate a Map implementation for every (K,V)-pair. An alternative would have been to use vtables.
Luckily a key in a protobuf map can only be integer types, bool and string. So the number of key types is bounded by the specification, while the number of value types is not i.e. any protobuf message can be a value in a map. Given these constraints we introduce one 'MapKeyOps' trait per key type e.g. MapKeyBOOLOps or MapKeyI32Ops. These traits need to be implemented for every value type e.g. 'impl MapKeyBOOLOps for i32' will implement 'Map::<bool, i32>'. In particular the MapKeyOps traits can also be implemented for generated messages without violating the orphan rule.
This CL also contains significant changes to the UPB runtime so that both upb.rs and cpp.rs export a similar interface to simplify the implementation in map.rs and the generated code.
This CL does not yet implement the Proxied trait.
PiperOrigin-RevId: 582951914
diff --git a/rust/cpp_kernel/cpp_api.cc b/rust/cpp_kernel/cpp_api.cc
index 1381611..97f2c3c 100644
--- a/rust/cpp_kernel/cpp_api.cc
+++ b/rust/cpp_kernel/cpp_api.cc
@@ -1,3 +1,4 @@
+#include "google/protobuf/map.h"
#include "google/protobuf/repeated_field.h"
extern "C" {
@@ -36,4 +37,61 @@
expose_repeated_field_methods(int64_t, i64);
#undef expose_repeated_field_methods
+
+#define expose_scalar_map_methods(key_ty, rust_key_ty, value_ty, \
+ rust_value_ty) \
+ google::protobuf::Map<key_ty, value_ty>* \
+ __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_new() { \
+ return new google::protobuf::Map<key_ty, value_ty>(); \
+ } \
+ void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_clear( \
+ google::protobuf::Map<key_ty, value_ty>* m) { \
+ m->clear(); \
+ } \
+ size_t __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_size( \
+ google::protobuf::Map<key_ty, value_ty>* m) { \
+ return m->size(); \
+ } \
+ void __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_insert( \
+ google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty val) { \
+ (*m)[key] = val; \
+ } \
+ bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_get( \
+ google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty* value) { \
+ auto it = m->find(key); \
+ if (it == m->end()) { \
+ return false; \
+ } \
+ *value = it->second; \
+ return true; \
+ } \
+ bool __pb_rust_Map_##rust_key_ty##_##rust_value_ty##_remove( \
+ google::protobuf::Map<key_ty, value_ty>* m, key_ty key, value_ty* value) { \
+ auto it = m->find(key); \
+ if (it == m->end()) { \
+ return false; \
+ } else { \
+ *value = it->second; \
+ m->erase(it); \
+ return true; \
+ } \
+ }
+
+#define expose_scalar_map_methods_for_key_type(key_ty, rust_key_ty) \
+ expose_scalar_map_methods(key_ty, rust_key_ty, int32_t, i32); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, uint32_t, u32); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, float, f32); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, double, f64); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, bool, bool); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, uint64_t, u64); \
+ expose_scalar_map_methods(key_ty, rust_key_ty, int64_t, i64);
+
+expose_scalar_map_methods_for_key_type(int32_t, i32);
+expose_scalar_map_methods_for_key_type(uint32_t, u32);
+expose_scalar_map_methods_for_key_type(bool, bool);
+expose_scalar_map_methods_for_key_type(uint64_t, u64);
+expose_scalar_map_methods_for_key_type(int64_t, i64);
+
+#undef expose_scalar_map_methods
+#undef expose_map_methods
}