|
8 | 8 | #include "google/protobuf/descriptor.h" |
9 | 9 | #include "google/protobuf/dynamic_message.h" |
10 | 10 | #include "google/protobuf/message.h" |
| 11 | +#include "google/protobuf/text_format.h" |
11 | 12 | #include "google/protobuf/unittest.pb.h" |
12 | 13 | #include "google/protobuf/proto_api.h" |
13 | 14 | #include "third_party/pybind11/include/pybind11/eval.h" |
@@ -137,10 +138,65 @@ auto ReprDynamicMessage(int value) { |
137 | 138 | return result_string; |
138 | 139 | } |
139 | 140 |
|
| 141 | +py::object CreateDynamicPoolMessage() { |
| 142 | + FileDescriptorProto file_descriptor; |
| 143 | + file_descriptor.set_name("test_file"); |
| 144 | + file_descriptor.set_package("test_package"); |
| 145 | + DescriptorProto* message_descriptor = file_descriptor.add_message_type(); |
| 146 | + message_descriptor->set_name("MyMessage"); |
| 147 | + FieldDescriptorProto* field_descriptor = message_descriptor->add_field(); |
| 148 | + field_descriptor->set_name("my_field"); |
| 149 | + field_descriptor->set_number(1); |
| 150 | + field_descriptor->set_label(FieldDescriptorProto::LABEL_OPTIONAL); |
| 151 | + field_descriptor->set_type(FieldDescriptorProto::TYPE_INT32); |
| 152 | + auto owned_pool = std::make_unique<DescriptorPool>(); |
| 153 | + if (!owned_pool->BuildFile(file_descriptor)) { |
| 154 | + throw std::runtime_error("Failed to build file descriptor"); |
| 155 | + } |
| 156 | + |
| 157 | + // Create a Python DescriptorPool from the C++ one. |
| 158 | + const PyProto_API* api = GetProtoApi(); |
| 159 | + auto py_pool = py::reinterpret_steal<py::object>( |
| 160 | + api->DescriptorPool_FromPool(std::move(owned_pool), nullptr)); |
| 161 | + if (!py_pool) { |
| 162 | + throw py::error_already_set(); |
| 163 | + } |
| 164 | + |
| 165 | + const DescriptorPool* pool = api->DescriptorPool_AsPool(py_pool.ptr()); |
| 166 | + if (!pool) { |
| 167 | + throw py::error_already_set(); |
| 168 | + } |
| 169 | + |
| 170 | + // Navigate through the C++ Descriptors, and create a Python message. |
| 171 | + const Descriptor* descriptor = |
| 172 | + pool->FindMessageTypeByName("test_package.MyMessage"); |
| 173 | + if (!descriptor) { |
| 174 | + throw std::runtime_error("Failed to find file descriptor"); |
| 175 | + } |
| 176 | + auto py_msg = |
| 177 | + py::reinterpret_steal<py::object>(api->NewMessage(descriptor, nullptr)); |
| 178 | + if (!py_msg) { |
| 179 | + throw py::error_already_set(); |
| 180 | + } |
| 181 | + Message* msg = api->GetMutableMessagePointer(py_msg.ptr()); |
| 182 | + if (!msg) { |
| 183 | + throw py::error_already_set(); |
| 184 | + } |
| 185 | + |
| 186 | + // Populate the message, and return it. |
| 187 | + if (!google::protobuf::TextFormat::ParseFromString("my_field: 42", msg)) { |
| 188 | + throw std::runtime_error("Failed to parse message"); |
| 189 | + } |
| 190 | + // This is safe: the Python object keeps a reference to the Python |
| 191 | + // DescriptorPool, which owns the C++ DescriptorPool. |
| 192 | + return py_msg; |
| 193 | +} |
| 194 | + |
140 | 195 | PYBIND11_MODULE(proto_api_test_ext, m) { |
141 | 196 | m.def("get_const_message", &GetConstMessage); |
142 | 197 | m.def("set_message_field_with_mutator", &SetMessageFieldWithMutator); |
143 | 198 | m.def("repr_dynamic_message", &ReprDynamicMessage); |
| 199 | + m.def("create_dynamic_pool_message", &CreateDynamicPoolMessage); |
144 | 200 | } |
145 | 201 |
|
146 | 202 | } // namespace python |
|
0 commit comments