|
|
|
// Protocol Buffers - Google's data interchange format
|
|
|
|
// Copyright 2023 Google LLC. All rights reserved.
|
|
|
|
// https://developers.google.com/protocol-buffers/
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
|
|
// in the documentation and/or other materials provided with the
|
|
|
|
// distribution.
|
|
|
|
// * Neither the name of Google LLC nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived from
|
|
|
|
// this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
#include "python/extension_dict.h"
|
|
|
|
|
|
|
|
#include "python/message.h"
|
|
|
|
#include "python/protobuf.h"
|
|
|
|
#include "upb/reflection/def.h"
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// ExtensionDict
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD;
|
|
|
|
PyObject* msg; // Owning ref to our parent pessage.
|
|
|
|
} PyUpb_ExtensionDict;
|
|
|
|
|
|
|
|
PyObject* PyUpb_ExtensionDict_New(PyObject* msg) {
|
|
|
|
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
|
|
|
|
PyUpb_ExtensionDict* ext_dict =
|
|
|
|
(void*)PyType_GenericAlloc(state->extension_dict_type, 0);
|
|
|
|
ext_dict->msg = msg;
|
|
|
|
Py_INCREF(ext_dict->msg);
|
|
|
|
return &ext_dict->ob_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionDict_FindExtensionByName(PyObject* _self,
|
|
|
|
PyObject* key) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
const char* name = PyUpb_GetStrData(key);
|
|
|
|
if (!name) {
|
|
|
|
PyErr_Format(PyExc_TypeError, "_FindExtensionByName expect a str");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(self->msg);
|
|
|
|
const upb_FileDef* file = upb_MessageDef_File(m);
|
|
|
|
const upb_DefPool* symtab = upb_FileDef_Pool(file);
|
|
|
|
const upb_FieldDef* ext = upb_DefPool_FindExtensionByName(symtab, name);
|
|
|
|
if (ext) {
|
|
|
|
return PyUpb_FieldDescriptor_Get(ext);
|
|
|
|
} else {
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionDict_FindExtensionByNumber(PyObject* _self,
|
|
|
|
PyObject* arg) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(self->msg);
|
|
|
|
const upb_MiniTable* l = upb_MessageDef_MiniTable(m);
|
|
|
|
const upb_FileDef* file = upb_MessageDef_File(m);
|
|
|
|
const upb_DefPool* symtab = upb_FileDef_Pool(file);
|
|
|
|
const upb_ExtensionRegistry* reg = upb_DefPool_ExtensionRegistry(symtab);
|
|
|
|
int64_t number = PyLong_AsLong(arg);
|
|
|
|
if (number == -1 && PyErr_Occurred()) return NULL;
|
|
|
|
const upb_MiniTableExtension* ext =
|
|
|
|
(upb_MiniTableExtension*)upb_ExtensionRegistry_Lookup(reg, l, number);
|
|
|
|
if (ext) {
|
|
|
|
const upb_FieldDef* f = upb_DefPool_FindExtensionByMiniTable(symtab, ext);
|
|
|
|
return PyUpb_FieldDescriptor_Get(f);
|
|
|
|
} else {
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PyUpb_ExtensionDict_Dealloc(PyUpb_ExtensionDict* self) {
|
|
|
|
PyUpb_Message_ClearExtensionDict(self->msg);
|
|
|
|
Py_DECREF(self->msg);
|
|
|
|
PyUpb_Dealloc(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionDict_RichCompare(PyObject* _self,
|
|
|
|
PyObject* _other, int opid) {
|
|
|
|
// Only equality comparisons are implemented.
|
|
|
|
if (opid != Py_EQ && opid != Py_NE) {
|
|
|
|
Py_INCREF(Py_NotImplemented);
|
|
|
|
return Py_NotImplemented;
|
|
|
|
}
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
bool equals = false;
|
|
|
|
if (PyObject_TypeCheck(_other, Py_TYPE(_self))) {
|
|
|
|
PyUpb_ExtensionDict* other = (PyUpb_ExtensionDict*)_other;
|
|
|
|
equals = self->msg == other->msg;
|
|
|
|
}
|
|
|
|
bool ret = opid == Py_EQ ? equals : !equals;
|
|
|
|
return PyBool_FromLong(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PyUpb_ExtensionDict_Contains(PyObject* _self, PyObject* key) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(self->msg, key);
|
|
|
|
if (!f) return -1;
|
|
|
|
upb_Message* msg = PyUpb_Message_GetIfReified(self->msg);
|
|
|
|
if (!msg) return 0;
|
|
|
|
if (upb_FieldDef_IsRepeated(f)) {
|
|
|
|
upb_MessageValue val = upb_Message_GetFieldByDef(msg, f);
|
|
|
|
return upb_Array_Size(val.array_val) > 0;
|
|
|
|
} else {
|
|
|
|
return upb_Message_HasFieldByDef(msg, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Py_ssize_t PyUpb_ExtensionDict_Length(PyObject* _self) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
upb_Message* msg = PyUpb_Message_GetIfReified(self->msg);
|
|
|
|
return msg ? upb_Message_ExtensionCount(msg) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionDict_Subscript(PyObject* _self, PyObject* key) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(self->msg, key);
|
|
|
|
if (!f) return NULL;
|
|
|
|
return PyUpb_Message_GetFieldValue(self->msg, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PyUpb_ExtensionDict_AssignSubscript(PyObject* _self, PyObject* key,
|
|
|
|
PyObject* val) {
|
|
|
|
PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
|
|
|
|
const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(self->msg, key);
|
|
|
|
if (!f) return -1;
|
|
|
|
if (val) {
|
|
|
|
return PyUpb_Message_SetFieldValue(self->msg, f, val, PyExc_TypeError);
|
|
|
|
} else {
|
|
|
|
PyUpb_Message_DoClearField(self->msg, f);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionIterator_New(PyObject* _ext_dict);
|
|
|
|
|
|
|
|
static PyMethodDef PyUpb_ExtensionDict_Methods[] = {
|
|
|
|
{"_FindExtensionByName", PyUpb_ExtensionDict_FindExtensionByName, METH_O,
|
|
|
|
"Finds an extension by name."},
|
|
|
|
{"_FindExtensionByNumber", PyUpb_ExtensionDict_FindExtensionByNumber,
|
|
|
|
METH_O, "Finds an extension by number."},
|
|
|
|
{NULL, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyType_Slot PyUpb_ExtensionDict_Slots[] = {
|
|
|
|
{Py_tp_dealloc, PyUpb_ExtensionDict_Dealloc},
|
|
|
|
{Py_tp_methods, PyUpb_ExtensionDict_Methods},
|
|
|
|
//{Py_tp_getset, PyUpb_ExtensionDict_Getters},
|
|
|
|
//{Py_tp_hash, PyObject_HashNotImplemented},
|
|
|
|
{Py_tp_richcompare, PyUpb_ExtensionDict_RichCompare},
|
|
|
|
{Py_tp_iter, PyUpb_ExtensionIterator_New},
|
|
|
|
{Py_sq_contains, PyUpb_ExtensionDict_Contains},
|
|
|
|
{Py_sq_length, PyUpb_ExtensionDict_Length},
|
|
|
|
{Py_mp_length, PyUpb_ExtensionDict_Length},
|
|
|
|
{Py_mp_subscript, PyUpb_ExtensionDict_Subscript},
|
|
|
|
{Py_mp_ass_subscript, PyUpb_ExtensionDict_AssignSubscript},
|
|
|
|
{0, NULL}};
|
|
|
|
|
|
|
|
static PyType_Spec PyUpb_ExtensionDict_Spec = {
|
|
|
|
PYUPB_MODULE_NAME ".ExtensionDict", // tp_name
|
|
|
|
sizeof(PyUpb_ExtensionDict), // tp_basicsize
|
|
|
|
0, // tp_itemsize
|
|
|
|
Py_TPFLAGS_DEFAULT, // tp_flags
|
|
|
|
PyUpb_ExtensionDict_Slots,
|
|
|
|
};
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// ExtensionIterator
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD;
|
|
|
|
PyObject* msg;
|
|
|
|
size_t iter;
|
|
|
|
} PyUpb_ExtensionIterator;
|
|
|
|
|
|
|
|
static PyObject* PyUpb_ExtensionIterator_New(PyObject* _ext_dict) {
|
|
|
|
PyUpb_ExtensionDict* ext_dict = (PyUpb_ExtensionDict*)_ext_dict;
|
|
|
|
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
|
|
|
|
PyUpb_ExtensionIterator* iter =
|
|
|
|
(void*)PyType_GenericAlloc(state->extension_iterator_type, 0);
|
|
|
|
if (!iter) return NULL;
|
|
|
|
iter->msg = ext_dict->msg;
|
|
|
|
iter->iter = kUpb_Message_Begin;
|
|
|
|
Py_INCREF(iter->msg);
|
|
|
|
return &iter->ob_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PyUpb_ExtensionIterator_Dealloc(void* _self) {
|
|
|
|
PyUpb_ExtensionIterator* self = (PyUpb_ExtensionIterator*)_self;
|
|
|
|
Py_DECREF(self->msg);
|
|
|
|
PyUpb_Dealloc(_self);
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject* PyUpb_ExtensionIterator_IterNext(PyObject* _self) {
|
|
|
|
PyUpb_ExtensionIterator* self = (PyUpb_ExtensionIterator*)_self;
|
|
|
|
upb_Message* msg = PyUpb_Message_GetIfReified(self->msg);
|
|
|
|
if (!msg) return NULL;
|
|
|
|
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(self->msg);
|
|
|
|
const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
|
|
|
|
while (true) {
|
|
|
|
const upb_FieldDef* f;
|
|
|
|
upb_MessageValue val;
|
|
|
|
if (!upb_Message_Next(msg, m, symtab, &f, &val, &self->iter)) return NULL;
|
|
|
|
if (upb_FieldDef_IsExtension(f)) return PyUpb_FieldDescriptor_Get(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyType_Slot PyUpb_ExtensionIterator_Slots[] = {
|
|
|
|
{Py_tp_dealloc, PyUpb_ExtensionIterator_Dealloc},
|
|
|
|
{Py_tp_iter, PyObject_SelfIter},
|
|
|
|
{Py_tp_iternext, PyUpb_ExtensionIterator_IterNext},
|
|
|
|
{0, NULL}};
|
|
|
|
|
|
|
|
static PyType_Spec PyUpb_ExtensionIterator_Spec = {
|
|
|
|
PYUPB_MODULE_NAME ".ExtensionIterator", // tp_name
|
|
|
|
sizeof(PyUpb_ExtensionIterator), // tp_basicsize
|
|
|
|
0, // tp_itemsize
|
|
|
|
Py_TPFLAGS_DEFAULT, // tp_flags
|
|
|
|
PyUpb_ExtensionIterator_Slots,
|
|
|
|
};
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Top Level
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
bool PyUpb_InitExtensionDict(PyObject* m) {
|
|
|
|
PyUpb_ModuleState* s = PyUpb_ModuleState_GetFromModule(m);
|
|
|
|
|
|
|
|
s->extension_dict_type = PyUpb_AddClass(m, &PyUpb_ExtensionDict_Spec);
|
|
|
|
s->extension_iterator_type = PyUpb_AddClass(m, &PyUpb_ExtensionIterator_Spec);
|
|
|
|
|
|
|
|
return s->extension_dict_type && s->extension_iterator_type;
|
|
|
|
}
|