Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
16 KiB

/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2009 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* Python extension exposing the core of upb: definitions, handlers,
* and a message type.
*/
#include <stddef.h>
#include <Python.h>
#include "upb/def.h"
static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; }
PyObject *PyUpb_Error(const char *str) {
PyErr_SetString(PyExc_TypeError, str);
return NULL;
}
int PyUpb_ErrorInt(const char *str) {
PyErr_SetString(PyExc_TypeError, str);
return -1;
}
/* PyUpb_Def ******************************************************************/
// All the def types share the same C layout, even though they are different
// Python types. For the moment we don't bother trying to make them an actual
// inheritance hierarchy.
typedef struct {
PyObject_HEAD;
upb_def *def;
} PyUpb_Def;
static void PyUpb_Def_dealloc(PyObject *obj) {
PyUpb_Def *def = (void*)obj;
upb_def_unref(def->def);
obj->ob_type->tp_free(obj);
}
/* Object cache ***************************************************************/
// For objects that are just wrappers around a C object pointer, we keep a
// cache mapping C pointer -> wrapper object. This allows us to consistently
// vend the same Python object given the same C object. This prevents us from
// creating too many Python objects unnecessarily. More importantly, it provides
// the expected semantics:
//
// if field.subdef is field.subdef:
// print "Sanity prevails."
//
// If we conjured up a new wrapper object every time, the above would not be
// true.
//
// The cost is having to put all such objects in a table, but since this only
// applies to schema-level objects (defs, handlers, etc) this seems acceptable.
// We do *not* have to put all message objects in this table.
//
// We use weak refs so that the cache does not prevent the wrapper objects from
// being collected. The table is stored as a static variable; to use
// sub-interpreters this would need to change, but I believe that using
// sub-interpreters is exceedingly rare in practice.
typedef struct {
PyObject_HEAD;
void *obj;
PyObject *weakreflist;
} PyUpb_ObjWrapper;
static PyObject *obj_cache = NULL;
static PyObject *weakref_callback = NULL;
static PyObject *PyUpb_ObjCacheDeleteCallback(PyObject *self, PyObject *ref) {
// Remove the value from the weak table.
PyUpb_ObjWrapper *tmp = (PyUpb_ObjWrapper*)PyWeakref_GetObject(ref);
char key[sizeof(void*) + 1];
key[sizeof(void*)] = '\0';
memcpy(key, &tmp->obj, sizeof(void*));
PyDict_DelItemString(obj_cache, key);
return Py_None;
}
static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) {
char key[sizeof(void*) + 1];
key[sizeof(void*)] = '\0';
memcpy(key, &obj, sizeof(void*));
PyObject *ref = PyDict_GetItemString(obj_cache, key);
if (!ref) {
PyUpb_ObjWrapper *tmp = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0);
tmp->obj = obj;
tmp->weakreflist = NULL;
ref = PyWeakref_NewRef((PyObject*)tmp, weakref_callback);
assert(ref);
PyDict_SetItemString(obj_cache, key, ref);
}
PyObject *ret = PyWeakref_GetObject(ref);
assert(ret);
return ret;
}
/* PyUpb_FieldDef *************************************************************/
static PyTypeObject PyUpb_FieldDefType;
static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val);
#define Check_FieldDef(o, badret) \
(void*)(((PyUpb_ObjWrapper*)o)->obj); do { \
if(!PyObject_TypeCheck(o, &PyUpb_FieldDefType)) { \
PyErr_SetString(PyExc_TypeError, "must be a upb.FieldDef"); \
return badret; \
} \
} while(0)
static PyObject *PyUpb_FieldDef_GetOrCreate(upb_fielddef *f) {
return PyUpb_ObjCacheGet(f, &PyUpb_FieldDefType);
}
static PyObject *PyUpb_FieldDef_new(PyTypeObject *subtype,
PyObject *args, PyObject *kwds) {
return PyUpb_ObjCacheGet(upb_fielddef_new(), subtype);
}
static int PyUpb_FieldDef_init(PyObject *self, PyObject *args, PyObject *kwds) {
if (!kwds) return 0;
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(kwds, &pos, &key, &value))
PyUpb_FieldDef_setattro(self, key, value);
return 0;
}
static void PyUpb_FieldDef_dealloc(PyObject *obj) {
PyUpb_ObjWrapper *wrapper = (void*)obj;
if (wrapper->weakreflist) PyObject_ClearWeakRefs(obj);
upb_fielddef_unref((upb_fielddef*)wrapper->obj);
obj->ob_type->tp_free(obj);
}
static PyObject *PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) {
upb_fielddef *f = Check_FieldDef(obj, NULL);
if (!upb_fielddef_ismutable(f)) {
PyErr_SetString(PyExc_TypeError, "fielddef is not mutable.");
return NULL;
}
const char *name = PyString_AsString(attr_name);
if (streql(name, "name")) {
const char *name = upb_fielddef_name(f);
return name == NULL ? Py_None : PyString_FromString(name);
} else if (streql(name, "number")) {
uint32_t num = upb_fielddef_number(f);
return num == 0 ? Py_None : PyInt_FromLong(num);
} else if (streql(name, "type")) {
uint8_t type = upb_fielddef_type(f);
return type == 0 ? Py_None : PyInt_FromLong(type);
} else if (streql(name, "label")) {
return PyInt_FromLong(upb_fielddef_label(f));
} else if (streql(name, "type_name")) {
const char *name = upb_fielddef_typename(f);
return name == NULL ? Py_None : PyString_FromString(name);
} else if (streql(name, "subdef")) {
// NYI;
return NULL;
} else if (streql(name, "msgdef")) {
// NYI;
return NULL;
} else {
return PyUpb_Error("Invalid fielddef member.");
}
}
static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val) {
upb_fielddef *f = Check_FieldDef(o, -1);
const char *field = PyString_AsString(key);
if (!upb_fielddef_ismutable(f))
return PyUpb_ErrorInt("fielddef is not mutable.");
if (streql(field, "name")) {
const char *name = PyString_AsString(val);
if (!name || !upb_fielddef_setname(f, name))
return PyUpb_ErrorInt("Invalid name");
} else if (streql(field, "number")) {
// TODO: should check truncation. Non-security issue.
// Non-int will return -1, which is already invalid as a field number.
if (!upb_fielddef_setnumber(f, PyInt_AsLong(val)))
return PyUpb_ErrorInt("Invalid number");
} else if (streql(field, "type")) {
// TODO: should check truncation. Non-security issue.
if (!upb_fielddef_settype(f, PyInt_AsLong(val)))
return PyUpb_ErrorInt("Invalid type");
} else if (streql(field, "label")) {
// TODO: should check truncation. Non-security issue.
if (!upb_fielddef_setlabel(f, PyInt_AsLong(val)))
return PyUpb_ErrorInt("Invalid label");
} else if (streql(field, "type_name")) {
const char *name = PyString_AsString(val);
if (!name || !upb_fielddef_settypename(f, name))
return PyUpb_ErrorInt("Invalid type_name");
} else if (streql(field, "default_value")) {
// NYI
return -1;
} else {
return PyUpb_ErrorInt("Invalid fielddef member.");
}
return 0;
}
static PyTypeObject PyUpb_FieldDefType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"upb.FieldDef", /* tp_name */
sizeof(PyUpb_ObjWrapper), /* tp_basicsize */
0, /* tp_itemsize */
&PyUpb_FieldDef_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* TODO */ /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
&PyUpb_FieldDef_getattro, /* tp_getattro */
&PyUpb_FieldDef_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
&PyUpb_FieldDef_init, /* tp_init */
0, /* tp_alloc */
&PyUpb_FieldDef_new, /* tp_new */
0, /* tp_free */
};
/* PyUpb_MessageDef ***********************************************************/
static PyTypeObject PyUpb_MessageDefType;
static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val);
#define Check_MessageDef(obj, badret) \
(void*)obj; do { \
if(!PyObject_TypeCheck(obj, &PyUpb_MessageDefType)) { \
PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \
return badret; \
} \
} while(0)
static PyObject *PyUpb_MessageDef_new(PyTypeObject *subtype,
PyObject *args, PyObject *kwds) {
PyUpb_Def *def = (PyUpb_Def*)subtype->tp_alloc(subtype, 0);
def->def = UPB_UPCAST(upb_msgdef_new());
return (PyObject*)def;
}
static int PyUpb_MessageDef_init(PyObject *self, PyObject *args, PyObject *kwds) {
if (!kwds) return 0;
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(kwds, &pos, &key, &value))
PyUpb_MessageDef_setattro(self, key, value);
return 0;
}
static PyObject *PyUpb_MessageDef_getattro(PyObject *obj, PyObject *attr_name) {
PyUpb_Def *def = Check_MessageDef(obj, NULL);
if (!upb_def_ismutable(def->def)) {
PyErr_SetString(PyExc_TypeError, "fielddef is not mutable.");
return NULL;
}
const char *name = PyString_AsString(attr_name);
if (streql(name, "fqname")) {
const char *fqname = upb_def_fqname(def->def);
return fqname == NULL ? Py_None : PyString_FromString(fqname);
}
return PyObject_GenericGetAttr(obj, attr_name);
}
static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val) {
return 0;
}
static PyObject *PyUpb_MessageDef_fields(PyObject *obj, PyObject *args) {
PyUpb_Def *def = Check_MessageDef(obj, NULL);
upb_msgdef *m = upb_downcast_msgdef(def->def);
PyObject *ret = PyList_New(0);
upb_msg_iter i;
for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) {
upb_fielddef *f = upb_msg_iter_field(i);
PyList_Append(ret, PyUpb_FieldDef_GetOrCreate(f));
}
return ret;
}
static PyMethodDef PyUpb_MessageDef_methods[] = {
{"fields", &PyUpb_MessageDef_fields, METH_NOARGS, "Returns list of fields."},
{NULL, NULL}
};
static PyTypeObject PyUpb_MessageDefType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"upb.MessageDef", /* tp_name */
sizeof(PyUpb_ObjWrapper), /* tp_basicsize */
0, /* tp_itemsize */
&PyUpb_Def_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* TODO */ /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
&PyUpb_MessageDef_getattro, /* tp_getattro */
&PyUpb_MessageDef_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyUpb_MessageDef_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
&PyUpb_MessageDef_init, /* tp_init */
0, /* tp_alloc */
&PyUpb_MessageDef_new, /* tp_new */
0, /* tp_free */
};
/* Toplevel *******************************************************************/
static PyMethodDef methods[] = {
{NULL, NULL}
};
// PyModule_AddObject steals a ref, but our object is statically allocated
// and must not be deleted.
#define PyUpb_AddType(mod, name, type) \
if (PyType_Ready(type) < 0) return; \
Py_INCREF(type); \
PyModule_AddObject(mod, name, (PyObject*)type);
PyMODINIT_FUNC initupb(void) {
PyObject *mod = Py_InitModule("upb", methods);
PyUpb_AddType(mod, "FieldDef", &PyUpb_FieldDefType);
PyUpb_AddType(mod, "MessageDef", &PyUpb_MessageDefType);
PyModule_AddIntConstant(mod, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL));
PyModule_AddIntConstant(mod, "LABEL_REQUIRED", UPB_LABEL(REQUIRED));
PyModule_AddIntConstant(mod, "LABEL_REPEATED", UPB_LABEL(REPEATED));
PyModule_AddIntConstant(mod, "TYPE_DOUBLE", UPB_TYPE(DOUBLE));
PyModule_AddIntConstant(mod, "TYPE_FLOAT", UPB_TYPE(FLOAT));
PyModule_AddIntConstant(mod, "TYPE_INT64", UPB_TYPE(INT64));
PyModule_AddIntConstant(mod, "TYPE_UINT64", UPB_TYPE(UINT64));
PyModule_AddIntConstant(mod, "TYPE_INT32", UPB_TYPE(INT32));
PyModule_AddIntConstant(mod, "TYPE_FIXED64", UPB_TYPE(FIXED64));
PyModule_AddIntConstant(mod, "TYPE_FIXED32", UPB_TYPE(FIXED32));
PyModule_AddIntConstant(mod, "TYPE_BOOL", UPB_TYPE(BOOL));
PyModule_AddIntConstant(mod, "TYPE_STRING", UPB_TYPE(STRING));
PyModule_AddIntConstant(mod, "TYPE_GROUP", UPB_TYPE(GROUP));
PyModule_AddIntConstant(mod, "TYPE_MESSAGE", UPB_TYPE(MESSAGE));
PyModule_AddIntConstant(mod, "TYPE_BYTES", UPB_TYPE(BYTES));
PyModule_AddIntConstant(mod, "TYPE_UINT32", UPB_TYPE(UINT32));
PyModule_AddIntConstant(mod, "TYPE_ENUM", UPB_TYPE(ENUM));
PyModule_AddIntConstant(mod, "TYPE_SFIXED32", UPB_TYPE(SFIXED32));
PyModule_AddIntConstant(mod, "TYPE_SFIXED64", UPB_TYPE(SFIXED64));
PyModule_AddIntConstant(mod, "TYPE_SINT32", UPB_TYPE(SINT32));
PyModule_AddIntConstant(mod, "TYPE_SINT64", UPB_TYPE(SINT64));
obj_cache = PyDict_New();
static PyMethodDef method = {
"WeakRefCallback", &PyUpb_ObjCacheDeleteCallback, METH_O, NULL};
PyObject *pyname = PyString_FromString(method.ml_name);
weakref_callback = PyCFunction_NewEx(&method, NULL, pyname);
Py_DECREF(pyname);
}