extension_dict.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: anuraag@google.com (Anuraag Agrawal)
  31. // Author: tibell@google.com (Johan Tibell)
  32. #include <google/protobuf/pyext/extension_dict.h>
  33. #include <google/protobuf/stubs/logging.h>
  34. #include <google/protobuf/stubs/common.h>
  35. #include <google/protobuf/descriptor.h>
  36. #include <google/protobuf/dynamic_message.h>
  37. #include <google/protobuf/message.h>
  38. #include <google/protobuf/pyext/descriptor.h>
  39. #include <google/protobuf/pyext/descriptor_pool.h>
  40. #include <google/protobuf/pyext/message.h>
  41. #include <google/protobuf/pyext/repeated_composite_container.h>
  42. #include <google/protobuf/pyext/repeated_scalar_container.h>
  43. #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
  44. #include <google/protobuf/stubs/shared_ptr.h>
  45. namespace google {
  46. namespace protobuf {
  47. namespace python {
  48. namespace extension_dict {
  49. PyObject* len(ExtensionDict* self) {
  50. #if PY_MAJOR_VERSION >= 3
  51. return PyLong_FromLong(PyDict_Size(self->values));
  52. #else
  53. return PyInt_FromLong(PyDict_Size(self->values));
  54. #endif
  55. }
  56. // TODO(tibell): Use VisitCompositeField.
  57. int ReleaseExtension(ExtensionDict* self,
  58. PyObject* extension,
  59. const FieldDescriptor* descriptor) {
  60. if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
  61. if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  62. if (repeated_composite_container::Release(
  63. reinterpret_cast<RepeatedCompositeContainer*>(
  64. extension)) < 0) {
  65. return -1;
  66. }
  67. } else {
  68. if (repeated_scalar_container::Release(
  69. reinterpret_cast<RepeatedScalarContainer*>(
  70. extension)) < 0) {
  71. return -1;
  72. }
  73. }
  74. } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  75. if (cmessage::ReleaseSubMessage(
  76. self->parent, descriptor,
  77. reinterpret_cast<CMessage*>(extension)) < 0) {
  78. return -1;
  79. }
  80. }
  81. return 0;
  82. }
  83. PyObject* subscript(ExtensionDict* self, PyObject* key) {
  84. const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
  85. if (descriptor == NULL) {
  86. return NULL;
  87. }
  88. if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
  89. return NULL;
  90. }
  91. if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
  92. descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
  93. return cmessage::InternalGetScalar(self->message, descriptor);
  94. }
  95. PyObject* value = PyDict_GetItem(self->values, key);
  96. if (value != NULL) {
  97. Py_INCREF(value);
  98. return value;
  99. }
  100. if (self->parent == NULL) {
  101. // We are in "detached" state. Don't allow further modifications.
  102. // TODO(amauryfa): Support adding non-scalars to a detached extension dict.
  103. // This probably requires to store the type of the main message.
  104. PyErr_SetObject(PyExc_KeyError, key);
  105. return NULL;
  106. }
  107. if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
  108. descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  109. PyObject* sub_message = cmessage::InternalGetSubMessage(
  110. self->parent, descriptor);
  111. if (sub_message == NULL) {
  112. return NULL;
  113. }
  114. PyDict_SetItem(self->values, key, sub_message);
  115. return sub_message;
  116. }
  117. if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
  118. if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  119. CMessageClass* message_class = cdescriptor_pool::GetMessageClass(
  120. cmessage::GetDescriptorPoolForMessage(self->parent),
  121. descriptor->message_type());
  122. if (message_class == NULL) {
  123. return NULL;
  124. }
  125. PyObject* py_container = repeated_composite_container::NewContainer(
  126. self->parent, descriptor, message_class);
  127. if (py_container == NULL) {
  128. return NULL;
  129. }
  130. PyDict_SetItem(self->values, key, py_container);
  131. return py_container;
  132. } else {
  133. PyObject* py_container = repeated_scalar_container::NewContainer(
  134. self->parent, descriptor);
  135. if (py_container == NULL) {
  136. return NULL;
  137. }
  138. PyDict_SetItem(self->values, key, py_container);
  139. return py_container;
  140. }
  141. }
  142. PyErr_SetString(PyExc_ValueError, "control reached unexpected line");
  143. return NULL;
  144. }
  145. int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
  146. const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
  147. if (descriptor == NULL) {
  148. return -1;
  149. }
  150. if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
  151. return -1;
  152. }
  153. if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL ||
  154. descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  155. PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite "
  156. "type");
  157. return -1;
  158. }
  159. if (self->parent) {
  160. cmessage::AssureWritable(self->parent);
  161. if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
  162. return -1;
  163. }
  164. }
  165. // TODO(tibell): We shouldn't write scalars to the cache.
  166. PyDict_SetItem(self->values, key, value);
  167. return 0;
  168. }
  169. PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) {
  170. const FieldDescriptor* descriptor =
  171. cmessage::GetExtensionDescriptor(extension);
  172. if (descriptor == NULL) {
  173. return NULL;
  174. }
  175. PyObject* value = PyDict_GetItem(self->values, extension);
  176. if (self->parent) {
  177. if (value != NULL) {
  178. if (ReleaseExtension(self, value, descriptor) < 0) {
  179. return NULL;
  180. }
  181. }
  182. if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor(
  183. self->parent, descriptor)) == NULL) {
  184. return NULL;
  185. }
  186. }
  187. if (PyDict_DelItem(self->values, extension) < 0) {
  188. PyErr_Clear();
  189. }
  190. Py_RETURN_NONE;
  191. }
  192. PyObject* HasExtension(ExtensionDict* self, PyObject* extension) {
  193. const FieldDescriptor* descriptor =
  194. cmessage::GetExtensionDescriptor(extension);
  195. if (descriptor == NULL) {
  196. return NULL;
  197. }
  198. if (self->parent) {
  199. return cmessage::HasFieldByDescriptor(self->parent, descriptor);
  200. } else {
  201. int exists = PyDict_Contains(self->values, extension);
  202. if (exists < 0) {
  203. return NULL;
  204. }
  205. return PyBool_FromLong(exists);
  206. }
  207. }
  208. PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) {
  209. ScopedPyObjectPtr extensions_by_name(PyObject_GetAttrString(
  210. reinterpret_cast<PyObject*>(self->parent), "_extensions_by_name"));
  211. if (extensions_by_name == NULL) {
  212. return NULL;
  213. }
  214. PyObject* result = PyDict_GetItem(extensions_by_name.get(), name);
  215. if (result == NULL) {
  216. Py_RETURN_NONE;
  217. } else {
  218. Py_INCREF(result);
  219. return result;
  220. }
  221. }
  222. PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number) {
  223. ScopedPyObjectPtr extensions_by_number(PyObject_GetAttrString(
  224. reinterpret_cast<PyObject*>(self->parent), "_extensions_by_number"));
  225. if (extensions_by_number == NULL) {
  226. return NULL;
  227. }
  228. PyObject* result = PyDict_GetItem(extensions_by_number.get(), number);
  229. if (result == NULL) {
  230. Py_RETURN_NONE;
  231. } else {
  232. Py_INCREF(result);
  233. return result;
  234. }
  235. }
  236. ExtensionDict* NewExtensionDict(CMessage *parent) {
  237. ExtensionDict* self = reinterpret_cast<ExtensionDict*>(
  238. PyType_GenericAlloc(&ExtensionDict_Type, 0));
  239. if (self == NULL) {
  240. return NULL;
  241. }
  242. self->parent = parent; // Store a borrowed reference.
  243. self->message = parent->message;
  244. self->owner = parent->owner;
  245. self->values = PyDict_New();
  246. return self;
  247. }
  248. void dealloc(ExtensionDict* self) {
  249. Py_CLEAR(self->values);
  250. self->owner.reset();
  251. Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
  252. }
  253. static PyMappingMethods MpMethods = {
  254. (lenfunc)len, /* mp_length */
  255. (binaryfunc)subscript, /* mp_subscript */
  256. (objobjargproc)ass_subscript,/* mp_ass_subscript */
  257. };
  258. #define EDMETHOD(name, args, doc) { #name, (PyCFunction)name, args, doc }
  259. static PyMethodDef Methods[] = {
  260. EDMETHOD(ClearExtension, METH_O, "Clears an extension from the object."),
  261. EDMETHOD(HasExtension, METH_O, "Checks if the object has an extension."),
  262. EDMETHOD(_FindExtensionByName, METH_O,
  263. "Finds an extension by name."),
  264. EDMETHOD(_FindExtensionByNumber, METH_O,
  265. "Finds an extension by field number."),
  266. { NULL, NULL }
  267. };
  268. } // namespace extension_dict
  269. PyTypeObject ExtensionDict_Type = {
  270. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  271. FULL_MODULE_NAME ".ExtensionDict", // tp_name
  272. sizeof(ExtensionDict), // tp_basicsize
  273. 0, // tp_itemsize
  274. (destructor)extension_dict::dealloc, // tp_dealloc
  275. 0, // tp_print
  276. 0, // tp_getattr
  277. 0, // tp_setattr
  278. 0, // tp_compare
  279. 0, // tp_repr
  280. 0, // tp_as_number
  281. 0, // tp_as_sequence
  282. &extension_dict::MpMethods, // tp_as_mapping
  283. PyObject_HashNotImplemented, // tp_hash
  284. 0, // tp_call
  285. 0, // tp_str
  286. 0, // tp_getattro
  287. 0, // tp_setattro
  288. 0, // tp_as_buffer
  289. Py_TPFLAGS_DEFAULT, // tp_flags
  290. "An extension dict", // tp_doc
  291. 0, // tp_traverse
  292. 0, // tp_clear
  293. 0, // tp_richcompare
  294. 0, // tp_weaklistoffset
  295. 0, // tp_iter
  296. 0, // tp_iternext
  297. extension_dict::Methods, // tp_methods
  298. 0, // tp_members
  299. 0, // tp_getset
  300. 0, // tp_base
  301. 0, // tp_dict
  302. 0, // tp_descr_get
  303. 0, // tp_descr_set
  304. 0, // tp_dictoffset
  305. 0, // tp_init
  306. };
  307. } // namespace python
  308. } // namespace protobuf
  309. } // namespace google