summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2011-08-08 16:33:48 -0700
committerJoshua Haberman <joshua@reverberate.org>2011-08-08 16:33:48 -0700
commit487bfdfc0603ab7bf5fad381f52b8932cbcd355e (patch)
treed7db8ecbb96f8890e86313153e58edec580337df
parent6981e468a3234b3f5439dec8178703a6364cfe03 (diff)
Begin port of Python extension to new APIs.
-rw-r--r--lang_ext/python/cext.c17
-rw-r--r--lang_ext/python/cext.h48
-rw-r--r--lang_ext/python/definition.c336
-rw-r--r--lang_ext/python/definition.h49
-rw-r--r--lang_ext/python/pb.c920
-rw-r--r--lang_ext/python/setup.py10
-rw-r--r--lang_ext/python/test.py14
-rw-r--r--lang_ext/python/upb.c190
-rw-r--r--lang_ext/python/upb/definition.py1
-rw-r--r--lang_ext/python/upb/pb.py1
-rw-r--r--upb/def.h6
11 files changed, 211 insertions, 1381 deletions
diff --git a/lang_ext/python/cext.c b/lang_ext/python/cext.c
deleted file mode 100644
index 59e8346..0000000
--- a/lang_ext/python/cext.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
-
-#include "cext.h"
-
-PyMODINIT_FUNC
-initcext(void)
-{
- PyObject *mod = Py_InitModule("upb.cext", NULL);
- (void)mod;
- initdefinition();
- initpb();
-}
diff --git a/lang_ext/python/cext.h b/lang_ext/python/cext.h
deleted file mode 100644
index f53e6e7..0000000
--- a/lang_ext/python/cext.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
-
-#ifndef UPB_PYTHON_CEXT_H_
-#define UPB_PYTHON_CEXT_H_
-
-#include <Python.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- PyObject_HEAD
- struct upb_context *context;
- PyObject *created_defs;
-} PyUpb_Context;
-
-typedef struct {
- PyObject_HEAD
- struct upb_msgdef *def;
- PyUpb_Context *context;
-} PyUpb_MsgDef;
-
-extern PyTypeObject PyUpb_MsgDefType;
-
-/* What format string should be passed to PyArg_ParseTuple to get just a raw
- * string of bytes and a length. */
-#if PY_MAJOR_VERSION >= 3
-#define BYTES_FORMAT "y#"
-#else
-#define BYTES_FORMAT "s#"
-#endif
-
-#define RETURN_BOOL(val) if(val) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; }
-
-extern PyMODINIT_FUNC initdefinition(void);
-extern PyMODINIT_FUNC initpb(void);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif
diff --git a/lang_ext/python/definition.c b/lang_ext/python/definition.c
deleted file mode 100644
index 8e8b852..0000000
--- a/lang_ext/python/definition.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * This file defines the Python module upb.definition. This module
- * defines the following Python classes, which wrap upb's internal
- * definitions:
- *
- * - upb.definition.MessageDefintion
- * - upb.definition.EnumDefinition (TODO)
- * - upb.definition.ServiceDefinition (TODO)
- *
- * We also define a class upb.definition.Context, which provides the
- * mechanism for loading the above definitions from .proto files or
- * from binary descriptors.
- *
- * Once these definitions are loaded, we can use them to create
- * the Python types for each .proto message type. That is covered
- * in other files.
- */
-
-#include "definition.h"
-#include "upb_context.h"
-#include "upb_msg.h"
-
-static PyTypeObject PyUpb_ContextType;
-static struct upb_strtable msgdefs;
-static struct upb_strtable contexts;
-
-struct msgtab_entry {
- struct upb_strtable_entry e;
- PyUpb_MsgDef *msgdef;
-};
-
-struct contexttab_entry {
- struct upb_strtable_entry e;
- PyUpb_Context *context;
-};
-
-#define CheckContext(obj) \
- (void*)obj; do { \
- if(!PyObject_TypeCheck(obj, &PyUpb_ContextType)) { \
- PyErr_SetString(PyExc_TypeError, "Must be a upb.Context"); \
- return NULL; \
- } \
- } while(0)
-
-/* upb.def.MessageDefinition **************************************************/
-
-/* Not implemented yet, but these methods will expose information about the
- * message definition (the upb_msgdef). */
-static PyMethodDef msgdef_methods[] = {
- {NULL, NULL}
-};
-
-static void msgdef_dealloc(PyObject *obj)
-{
- PyUpb_MsgDef *md_obj = (void*)obj;
- Py_DECREF(md_obj->context);
- obj->ob_type->tp_free(obj);
-}
-
-PyTypeObject PyUpb_MsgDefType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "upb.definition.MessageDefinition", /* tp_name */
- sizeof(PyUpb_MsgDef), /* tp_basicsize */
- 0, /* tp_itemsize */
- msgdef_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- msgdef_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 */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* Can't be created in Python. */ /* tp_new */
- 0, /* tp_free */
-};
-
-/* upb.Context ****************************************************************/
-
-static PyObject *context_parsefds(PyObject *_context, PyObject *args)
-{
- PyUpb_Context *context = CheckContext(_context);
- struct upb_string str;
- if(!PyArg_ParseTuple(args, BYTES_FORMAT, &str.ptr, &str.byte_len))
- return NULL;
- str.byte_size = 0; /* We don't own that mem. */
-
- if(!upb_context_parsefds(context->context, &str)) {
- /* TODO: an appropriate error. */
- PyErr_SetString(PyExc_TypeError, "Failed to parse."); \
- return NULL; \
- }
- Py_RETURN_NONE;
-}
-
-static PyObject *get_or_create_def(struct upb_symtab_entry *e)
-{
- switch(e->type) {
- case UPB_SYM_MESSAGE: return (PyObject*)get_or_create_msgdef(e->ref.msg);
- case UPB_SYM_ENUM:
- case UPB_SYM_SERVICE:
- case UPB_SYM_EXTENSION:
- default: fprintf(stderr, "upb.pb, not implemented.\n"); abort(); return NULL;
- }
-}
-
-static PyUpb_Context *get_or_create_context(struct upb_context *context)
-{
- PyUpb_Context *pycontext = NULL;
- struct upb_string str = {.ptr = (char*)&context, .byte_len = sizeof(void*)};
- struct contexttab_entry *e = upb_strtable_lookup(&contexts, &str);
- if(!e) {
- pycontext = (void*)PyUpb_ContextType.tp_alloc(&PyUpb_ContextType, 0);
- pycontext->context = context;
- struct contexttab_entry new_e = {
- .e = {.key = {.ptr = (char*)&pycontext->context, .byte_len = sizeof(void*)}},
- .context = pycontext
- };
- upb_strtable_insert(&contexts, &new_e.e);
- } else {
- pycontext = e->context;
- Py_INCREF(pycontext);
- }
- return pycontext;
-}
-
-PyUpb_MsgDef *get_or_create_msgdef(struct upb_msgdef *def)
-{
- PyUpb_MsgDef *pydef = NULL;
- struct upb_string str = {.ptr = (char*)&def, .byte_len = sizeof(void*)};
- struct msgtab_entry *e = upb_strtable_lookup(&msgdefs, &str);
- if(!e) {
- pydef = (void*)PyUpb_MsgDefType.tp_alloc(&PyUpb_MsgDefType, 0);
- pydef->def = def;
- pydef->context = get_or_create_context(def->context);
- struct msgtab_entry new_e = {
- .e = {.key = {.ptr = (char*)&pydef->def, .byte_len = sizeof(void*)}},
- .msgdef = pydef
- };
- upb_strtable_insert(&msgdefs, &new_e.e);
- } else {
- pydef = e->msgdef;
- Py_INCREF(pydef);
- }
- return pydef;
-}
-
-static PyObject *context_lookup(PyObject *self, PyObject *args)
-{
- PyUpb_Context *context = CheckContext(self);
- struct upb_string str;
- if(!PyArg_ParseTuple(args, "s#", &str.ptr, &str.byte_len))
- return NULL;
- str.byte_size = 0; /* We don't own that mem. */
-
- struct upb_symtab_entry e;
- if(upb_context_lookup(context->context, &str, &e)) {
- return get_or_create_def(&e);
- } else {
- Py_RETURN_NONE;
- }
-}
-
-static PyObject *context_resolve(PyObject *self, PyObject *args)
-{
- PyUpb_Context *context = CheckContext(self);
- struct upb_string str;
- struct upb_string base;
- if(!PyArg_ParseTuple(args, "s#s#", &base.ptr, &base.byte_len,
- &str.ptr, &str.byte_len))
- return NULL;
- str.byte_size = 0; /* We don't own that mem. */
-
- struct upb_symtab_entry e;
- if(upb_context_resolve(context->context, &base, &str, &e)) {
- return get_or_create_def(&e);
- } else {
- Py_RETURN_NONE;
- }
-}
-
-/* Callback for upb_context_enumerate below. */
-static void add_string(void *udata, struct upb_symtab_entry *entry)
-{
- PyObject *list = udata;
- struct upb_string *s = &entry->e.key;
- /* TODO: check return. */
- PyObject *str = PyString_FromStringAndSize(s->ptr, s->byte_len);
- PyList_Append(list, str);
- Py_DECREF(str);
-}
-
-static PyObject *context_symbols(PyObject *self, PyObject *args)
-{
- PyUpb_Context *context = CheckContext(self);
- PyObject *list = PyList_New(0); /* TODO: check return. */
- upb_context_enumerate(context->context, add_string, list);
- return list;
-}
-
-static PyMethodDef context_methods[] = {
- {"parse_file_descriptor_set", context_parsefds, METH_VARARGS,
- "Parses a string containing a serialized FileDescriptorSet and adds its "
- "definitions to the context."
- },
- {"lookup", context_lookup, METH_VARARGS,
- "Finds a symbol by fully-qualified name (eg. foo.bar.MyType)."
- },
- {"resolve", context_resolve, METH_VARARGS,
- "Finds a symbol by a possibly-relative name, which will be interpreted "
- "in the context of the given base."
- },
- {"symbols", context_symbols, METH_NOARGS,
- "Returns a list of symbol names that are defined in this context."
- },
- {NULL, NULL}
-};
-
-static PyObject *context_new(PyTypeObject *subtype,
- PyObject *args, PyObject *kwds)
-{
- PyUpb_Context *obj = (void*)subtype->tp_alloc(subtype, 0);
- obj->context = upb_context_new();
- struct contexttab_entry e = {
- .e = {.key = {.ptr = (char*)&obj->context, .byte_len = sizeof(void*)}},
- .context = obj
- };
- upb_strtable_insert(&contexts, &e.e);
- return (void*)obj;
-}
-
-static void context_dealloc(PyObject *obj)
-{
- PyUpb_Context *c = (void*)obj;
- upb_context_unref(c->context);
- /* TODO: once strtable supports delete. */
- //struct upb_string ptrstr = {.ptr = (char*)&c->context, .byte_len = sizeof(void*)};
- //upb_strtable_delete(&contexts, &ptrstr);
- obj->ob_type->tp_free(obj);
-}
-
-static PyTypeObject PyUpb_ContextType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "upb.definition.Context", /* tp_name */
- sizeof(PyUpb_Context), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)context_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- context_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 */
- 0, /* tp_init */
- 0, /* tp_alloc */
- context_new, /* tp_new */
- 0, /* tp_free */
-};
-
-static PyMethodDef methods[] = {
- {NULL, NULL}
-};
-
-PyMODINIT_FUNC
-initdefinition(void)
-{
- if(PyType_Ready(&PyUpb_ContextType) < 0) return;
- if(PyType_Ready(&PyUpb_MsgDefType) < 0) return;
-
- /* PyModule_AddObject steals a reference. These objects are statically
- * allocated and must not be deleted, so we increment their refcount. */
- Py_INCREF(&PyUpb_ContextType);
- Py_INCREF(&PyUpb_MsgDefType);
-
- PyObject *mod = Py_InitModule("upb.cext.definition", methods);
- PyModule_AddObject(mod, "Context", (PyObject*)&PyUpb_ContextType);
- PyModule_AddObject(mod, "MessageDefinition", (PyObject*)&PyUpb_MsgDefType);
-
- upb_strtable_init(&contexts, 8, sizeof(struct contexttab_entry));
- upb_strtable_init(&msgdefs, 16, sizeof(struct msgtab_entry));
-}
diff --git a/lang_ext/python/definition.h b/lang_ext/python/definition.h
deleted file mode 100644
index f7162cf..0000000
--- a/lang_ext/python/definition.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * See def.h for a general description. These definitions
- * must be shared so that specific Python message types (for the
- * different proto APIs) can have access to the C definitions. */
-
-#ifndef UPB_PYTHON_DEFINITION_H_
-#define UPB_PYTHON_DEFINITION_H_
-
-#include <Python.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- PyObject_HEAD
- struct upb_context *context;
-} PyUpb_Context;
-
-typedef struct {
- PyObject_HEAD
- struct upb_msgdef *def;
- PyUpb_Context *context;
-} PyUpb_MsgDef;
-
-extern PyTypeObject PyUpb_MsgDefType;
-
-/* What format string should be passed to PyArg_ParseTuple to get just a raw
- * string of bytes and a length. */
-#if PY_MAJOR_VERSION >= 3
-#define BYTES_FORMAT "y#"
-#else
-#define BYTES_FORMAT "s#"
-#endif
-
-PyUpb_MsgDef *get_or_create_msgdef(struct upb_msgdef *def);
-
-#define RETURN_BOOL(val) if(val) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; }
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif
diff --git a/lang_ext/python/pb.c b/lang_ext/python/pb.c
deleted file mode 100644
index 70d32d7..0000000
--- a/lang_ext/python/pb.c
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2009 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * This file implements an interface to Python that is compatible
- * (as much as possible) with proto1 (the first implementation of
- * protocol buffers, which is only released internally to Google).
- */
-
-#include <Python.h>
-#include <stddef.h>
-#include "upb_mm.h"
-#include "definition.h"
-
-/* Opcodes that describe all of the operations you can perform on a field of a
- * protobuf from Python. For example, foo.has_bar() uses opcode OP_HAS. */
-typedef enum {
- /* For non-repeated fields. */
- OP_HAS,
- /* For non-repeated fields that are not submessages. */
- OP_SET,
- /* For non-repeated message fields. */
- OP_MUTABLE,
-
- /* For repeated fields. */
- OP_SIZE, OP_LIST, OP_ADD,
-
- /* For all types of fields. */
- OP_GET, OP_CLEAR
-} PyUpb_PbBoundFieldOpCode;
-
-const char *opcode_names[] = {
- "OP_HAS", "OP_SET", "OP_MUTABLE", "OP_SIZE", "OP_LIST", "OP_ADD", "OP_GET", "OP_CLEAR"
-};
-
-/* Structures for the Python objects we define. */
-
-/* Callable that will create a new message object of a specific type. In this
- * sense it sort of "pretends" to be a type, but it is not actually a type. */
-typedef struct {
- PyObject_HEAD;
- PyUpb_MsgDef *def;
-} PyUpb_PbMsgCreator;
-
-/* Message object. All messages use this structure and have the same Python
- * type (even if their .proto types are different). The type dictionary for
- * this type does not include field accessors -- those are dynamically looked
- * up in msg_getattro. */
-typedef struct {
- PyObject_HEAD;
- struct upb_mm_ref ref;
- PyUpb_MsgDef *def;
-} PyUpb_PbMsg;
-
-/* Represents a "bound" operation like obj.has_foo, that will perform the
- * operation when called. This is necessary because proto1 has all of its
- * operations modeled as methods, so one calls obj.has_foo(), not obj.has_foo
- * alone. */
-typedef struct {
- PyObject_HEAD;
- PyUpb_PbMsg *msg;
- struct upb_fielddef *f;
- PyUpb_PbBoundFieldOpCode code;
-} PyUpb_PbBoundFieldOp;
-
-static PyTypeObject PyUpb_PbMsgCreatorType;
-static PyTypeObject PyUpb_PbMsgType;
-static PyTypeObject PyUpb_PbBoundFieldOpType;
-
-#define Check_MsgCreator(obj) \
- (void*)obj; do { \
- if(!PyObject_TypeCheck(obj, &PyUpb_PbMsgCreatorType)) { \
- PyErr_SetString(PyExc_TypeError, "must be a MessageCreator"); \
- return NULL; \
- } \
- } while(0)
-
-#define Check_Message(obj) \
- (void*)obj; do { \
- if(!PyObject_TypeCheck(obj, &PyUpb_PbMsgType)) { \
- PyErr_SetString(PyExc_TypeError, "must be a Message"); \
- return NULL; \
- } \
- } while(0)
-
-#define Check_BoundFieldOp(obj) \
- (void*)obj; do { \
- if(!PyObject_TypeCheck(obj, &PyUpb_PbBoundFieldOpType)) { \
- PyErr_SetString(PyExc_TypeError, "must be a BoundFieldOp"); \
- return NULL; \
- } \
- } while(0)
-
-#define EXPECT_NO_ARGS if(!PyArg_ParseTuple(args, "")) return NULL;
-#define MMREF_TO_PYOBJ(mmref) (PyObject*)((char*)(mmref)-offsetof(PyUpb_PbMsg, ref))
-
-static struct upb_mm_ref *NewPyRef(struct upb_mm_ref *fromref,
- union upb_mmptr p, upb_mm_ptrtype type)
-{
- (void)fromref; /* Don't care. */
- struct upb_mm_ref *ref = NULL;
- switch(type) {
- case UPB_MM_MSG_REF: {
- PyUpb_PbMsg *msg = (void*)PyUpb_PbMsgType.tp_alloc(&PyUpb_PbMsgType, 0);
- msg->def = get_or_create_msgdef(p.msg->def); /* gets a ref. */
- ref = &msg->ref;
- break;
- }
- case UPB_MM_STR_REF: {
- }
- case UPB_MM_ARR_REF: {
- }
- default: assert(false); abort(); break; /* Shouldn't happen. */
- }
- return ref;
-}
-
-struct upb_mm pymm = {NewPyRef};
-
-/* upb.pb.BoundFieldOp ********************************************************/
-
-static PyObject *upb_to_py(union upb_value_ptr p, upb_field_type_t type)
-{
- switch(type) {
- default:
- PyErr_SetString(PyExc_RuntimeError, "internal: unexpected type");
- return NULL;
- case UPB_TYPENUM(DOUBLE):
- return PyFloat_FromDouble(*p._double);
- case UPB_TYPENUM(FLOAT):
- return PyFloat_FromDouble(*p._float);
- case UPB_TYPENUM(INT64):
- case UPB_TYPENUM(SINT64):
- case UPB_TYPENUM(SFIXED64):
- return PyLong_FromLongLong(*p.int64);
- case UPB_TYPENUM(UINT64):
- case UPB_TYPENUM(FIXED64):
- return PyLong_FromUnsignedLongLong(*p.uint64);
- case UPB_TYPENUM(SFIXED32):
- case UPB_TYPENUM(SINT32):
- case UPB_TYPENUM(INT32):
- case UPB_TYPENUM(ENUM):
-#if PY_MAJOR_VERSION >= 3
- return PyLong_FromLong(*p.int32);
-#else
- return PyInt_FromLong(*p.int32);
-#endif
-
- case UPB_TYPENUM(FIXED32):
- case UPB_TYPENUM(UINT32):
- return PyLong_FromLong(*p.uint32);
- case UPB_TYPENUM(BOOL):
- RETURN_BOOL(*p._bool);
- case UPB_TYPENUM(STRING):
- case UPB_TYPENUM(BYTES):
- /* Py3k will distinguish between these two. */
- return PyString_FromStringAndSize((*p.str)->ptr, (*p.str)->byte_len);
- case UPB_TYPENUM(GROUP):
- case UPB_TYPENUM(MESSAGE): {
- union upb_mmptr mmptr = upb_mmptr_read(p, UPB_MM_MSG_REF);
- bool created;
- struct upb_mm_ref *ref = upb_mm_getref(mmptr, UPB_MM_MSG_REF, &pymm, &created);
- PyObject *obj = MMREF_TO_PYOBJ(ref);
- if(!created) Py_INCREF(obj);
- return obj;
- }
- }
-}
-
-static long convert_to_long(PyObject *val, long lobound, long hibound, bool *ok)
-{
- PyObject *o = PyNumber_Int(val);
- if(!o) {
- PyErr_SetString(PyExc_OverflowError, "could not convert to long");
- *ok = false;
- return -1;
- }
- long longval = PyInt_AS_LONG(o);
- if(longval > hibound || longval < lobound) {
- PyErr_SetString(PyExc_OverflowError, "value outside type bounds");
- *ok = false;
- return -1;
- }
- *ok = true;
- return longval;
-}
-
-static void set_upbscalarfield(union upb_value_ptr p, PyObject *val,
- upb_field_type_t type)
-{
- switch(type) {
- default:
- PyErr_SetString(PyExc_RuntimeError, "internal error");
- return;
- case UPB_TYPENUM(DOUBLE): {
- PyObject *o = PyNumber_Float(val);
- if(!o) {
- PyErr_SetString(PyExc_ValueError, "could not convert to double");
- return;
- }
- *p._double = PyFloat_AS_DOUBLE(o);
- return;
- }
- case UPB_TYPENUM(FLOAT): {
- PyObject *o = PyNumber_Float(val);
- if(!o) {
- PyErr_SetString(PyExc_ValueError, "could not convert to float");
- return;
- }
- *p._float = PyFloat_AS_DOUBLE(o);
- return;
- }
- case UPB_TYPENUM(INT64):
- case UPB_TYPENUM(SINT64):
- case UPB_TYPENUM(SFIXED64): {
-#if LONG_MAX >= INT64_MAX
- bool ok;
- long longval = convert_to_long(val, INT64_MIN, INT64_MAX, &ok);
- if(ok) *p.int32 = longval;
- return;
-#else
- PyObject *o = PyNumber_Long(val);
- if(!o) {
- PyErr_SetString(PyExc_ValueError, "could not convert to int64");
- return;
- }
- *p.int64 = PyLong_AsLongLong(o);
- return;
-#endif
- }
- case UPB_TYPENUM(UINT64):
- case UPB_TYPENUM(FIXED64): {
- PyObject *o = PyNumber_Long(val);
- if(!o) {
- PyErr_SetString(PyExc_ValueError, "could not convert to uint64");
- return;
- }
- *p.uint64 = PyLong_AsUnsignedLongLong(o);
- return;
- }
- case UPB_TYPENUM(SFIXED32):
- case UPB_TYPENUM(SINT32):
- case UPB_TYPENUM(INT32):
- case UPB_TYPENUM(ENUM): {
- bool ok;
- long longval = convert_to_long(val, INT32_MIN, INT32_MAX, &ok);
- if(ok) *p.int32 = longval;
- return;
- }
-
- case UPB_TYPENUM(FIXED32):
- case UPB_TYPENUM(UINT32): {
-#if LONG_MAX >= UINT32_MAX
- bool ok;
- long longval = convert_to_long(val, 0, UINT32_MAX, &ok);
- if(ok) *p.int32 = longval;
- return;
-#else
- PyObject *o = PyNumber_Long(val);
- if(!o) {
- PyErr_SetString(PyExc_ValueError, "could not convert to uint32");
- return;
- }
- *p.uint32 = PyLong_AsUnsignedLong(o);
- return;
-#endif
- }
-
- case UPB_TYPENUM(BOOL):
- if(!PyBool_Check(val)) {
- PyErr_SetString(PyExc_ValueError, "should be true or false");
- return;
- }
- if(val == Py_True) *p._bool = true;
- else if(val == Py_False) *p._bool = false;
- else PyErr_SetString(PyExc_RuntimeError, "not true or false?");
- return;
-
- case UPB_TYPENUM(STRING):
- case UPB_TYPENUM(BYTES): {
- size_t len = PyString_GET_SIZE(val);
- upb_string_resize(*p.str, len);
- memcpy((*p.str)->ptr, PyString_AS_STRING(val), len);
- return;
- }
- }
-}
-
-static bool check_py_type(PyObject *obj, upb_field_type_t type)
-{
- /* TODO */
- return true;
-}
-
-PyObject* fieldop_call(PyObject *callable, PyObject *args, PyObject *kw)
-{
- PyUpb_PbBoundFieldOp *op = Check_BoundFieldOp(callable);
- PyUpb_PbMsg *pymsg = op->msg;
- struct upb_mm_ref *msgref = &(pymsg->ref);
- struct upb_msg *msg = pymsg->ref.p.msg;
- struct upb_fielddef *f = op->f;
- union upb_value_ptr p = upb_msg_getptr(msg, f);
- switch(op->code) {
- case OP_HAS:
- /* obj.has_foo() */
- EXPECT_NO_ARGS;
- RETURN_BOOL(upb_msg_isset(msg, f));
- case OP_SET: {
- PyObject *val;
- if(upb_isarray(f)) {
- /* obj.set_repeatedfoo(i, val) */
- int i;
- if(!PyArg_ParseTuple(args, "iO", &i, &val)) return NULL;
- if(!upb_msg_isset(msg, f) || i >= (*p.arr)->len) {
- PyErr_SetString(PyExc_IndexError, "assignment to invalid index");
- return NULL;
- }
- p = upb_array_getelementptr(*p.arr, i);
- } else {
- /* obj.set_foo(val) */
- if(!PyArg_ParseTuple(args, "O", &val)) return NULL;
- }
- set_upbscalarfield(p, val, f->type);
- if(PyErr_Occurred()) return NULL;
- Py_RETURN_NONE;
- }
- case OP_MUTABLE: {
- /* obj.mutable_scalarmsg() */
- EXPECT_NO_ARGS;
- bool created;
- PyObject *obj = MMREF_TO_PYOBJ(upb_mm_getfieldref(msgref, f, &created));
- if(!created) Py_INCREF(obj);
- return obj;
- }
-
- /* For repeated fields. */
- case OP_SIZE: {
- /* obj.repeatedfoo_size() */
- EXPECT_NO_ARGS;
- long len =
- upb_msg_isset(msg, f) ? (*upb_msg_getptr(msg, f).arr)->len : 0;
- return PyInt_FromLong(len);
- }
- case OP_LIST:
- /* obj.repeatedfoo_list() */
- case OP_ADD: {
- /* Parse/Verify the args. */
- PyObject *val;
- if(upb_issubmsg(f)) {
- /* obj.add_submsgfoo() # returns the new submsg */
- EXPECT_NO_ARGS;
- } else {
- /* obj.add_scalarfoo(val) */
- if(!PyArg_ParseTuple(args, "O", &val)) return NULL;
- if(!check_py_type(val, f->type)) return NULL;
- }
-
- upb_arraylen_t len = (*p.arr)->len;
- union upb_value_ptr elem_p = upb_array_getelementptr(*p.arr, len);
- upb_array_append(*p.arr);
-
- if(upb_issubmsg(f)) {
- /* string or submsg. */
- bool created;
- upb_mm_ptrtype type = upb_elem_ptrtype(f);
- union upb_mmptr mmptr = upb_mmptr_read(elem_p, type);
- struct upb_mm_ref *valref = upb_mm_getref(mmptr, type, &pymm, &created);
- assert(created);
- PyObject *obj = MMREF_TO_PYOBJ(valref);
- return obj;
- } else {
- set_upbscalarfield(elem_p, val, f->type);
- if(PyErr_Occurred()) return NULL;
- Py_RETURN_NONE;
- }
- }
-
- /* For all fields. */
- case OP_GET: {
- if(upb_isarray(f)) {
- /* obj.repeatedfoo(i) */
- int i;
- if(!PyArg_ParseTuple(args, "i", &i)) return NULL;
- if(!upb_msg_isset(msg, f) || i >= (*p.arr)->len) {
- PyErr_SetString(PyExc_IndexError, "get from invalid index");
- return NULL;
- }
- p = upb_array_getelementptr(*p.arr, i);
- } else {
- /* obj.foo() */
- EXPECT_NO_ARGS;
- }
- return upb_to_py(p, f->type);
- }
- case OP_CLEAR:
- /* obj.clear_foo() */
- EXPECT_NO_ARGS;
- upb_mm_msgclear(msgref, f);
- Py_RETURN_NONE;
-
- default:
- PyErr_SetString(PyExc_RuntimeError, "invalid bound field opcode.");
- return NULL;
- }
-}
-
-static void fieldop_dealloc(PyObject *obj)
-{
- PyUpb_PbBoundFieldOp *op = (void*)obj;
- Py_DECREF(op->msg);
- obj->ob_type->tp_free(obj);
-}
-
-static PyObject *fieldop_repr(PyObject *obj)
-{
- PyUpb_PbBoundFieldOp *op = Check_BoundFieldOp(obj);
- struct upb_string *name = op->msg->def->def->descriptor->name;
- /* Need to get a NULL-terminated copy of name since PyString_FromFormat
- * doesn't support ptr+len. */
- PyObject *nameobj = PyString_FromStringAndSize(name->ptr, name->byte_len);
- struct google_protobuf_FieldDescriptorProto *fd =
- upb_msg_field_descriptor(op->f, op->msg->def->def);
- PyObject *fieldnameobj = PyString_FromStringAndSize(fd->name->ptr, fd->name->byte_len);
- PyObject *ret =
- PyString_FromFormat("<upb.pb.BoundFieldOp field='%s', op=%s, msgtype='%s'>",
- PyString_AS_STRING(fieldnameobj),
- opcode_names[op->code], PyString_AS_STRING(nameobj));
- Py_DECREF(nameobj);
- Py_DECREF(fieldnameobj);
- return ret;
-}
-
-static PyTypeObject PyUpb_PbBoundFieldOpType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "upb.pb.BoundFieldOp", /* tp_name */
- sizeof(PyUpb_PbBoundFieldOp), /* tp_basicsize */
- 0, /* tp_itemsize */
- fieldop_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- fieldop_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- fieldop_call, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* 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 */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* Can't be created from Python. */ /* tp_new */
- 0, /* tp_free */
-};
-
-/* upb.pb.Message *************************************************************/
-
-#define Check_SameProtoType(obj1, obj2) \
- do { \
- if(self->ob_type != other->ob_type) { \
- PyErr_SetString(PyExc_TypeError, "other must be of the same type"); \
- return NULL; \
- } \
- } while(0);
-
-static PyObject *msg_clear(PyObject *self, PyObject *args)
-{
- (void)args;
- PyUpb_PbMsg *msg = Check_Message(self);
- upb_mm_msgclear_all(&msg->ref);
- Py_RETURN_NONE;
-}
-
-//static PyObject *msg_encode(PyObject *self, PyObject *args)
-//{
-// (void)args;
-// PyUpb_PbMsg *msg = Check_Message(self);
-// struct upb_msgsizes *sizes = upb_msgsizes_new();
-// struct upb_msg *upb_msg = msg->ref.p.msg;
-// upb_msgsizes_read(sizes, upb_msg);
-//
-// size_t size = upb_msgsizes_totalsize(sizes);
-// PyObject *str = PyString_FromStringAndSize(NULL, size);
-// if(!str) return NULL;
-// char *strbuf = PyString_AS_STRING(str);
-//
-// bool success = upb_msg_serialize_all(upb_msg, sizes, strbuf);
-// upb_msgsizes_free(sizes);
-// if(success) {
-// return str;
-// } else {
-// /* TODO: better error than TypeError. */
-// PyErr_SetString(PyExc_TypeError, "Error serializing protobuf.");
-// return NULL;
-// }
-//}
-
-static PyObject *msg_equals(PyObject *self, PyObject *other)
-{
- PyUpb_PbMsg *msg1 = Check_Message(self);
- PyUpb_PbMsg *msg2 = Check_Message(other);
- Check_SameProtoType(msg1, msg2);
- RETURN_BOOL(upb_msg_eql(msg1->ref.p.msg, msg2->ref.p.msg, true))
-}
-
-static PyObject *msg_isinitialized(PyObject *self, PyObject *args)
-{
- (void)args;
- PyUpb_PbMsg *msg = Check_Message(self);
- RETURN_BOOL(upb_msg_all_required_fields_set(msg->ref.p.msg))
-}
-
-static PyObject *msg_parsefromstring(PyObject *self, PyObject *args)
-{
- PyUpb_PbMsg *msg = Check_Message(self);
- char *strdata;
- size_t strlen;
- if(!PyArg_ParseTuple(args, BYTES_FORMAT, &strdata, &strlen))
- return NULL;
-
- if(upb_msg_parsestr(msg->ref.p.msg, strdata, strlen) != UPB_STATUS_OK) {
- /* TODO: better error than TypeError. */
- PyErr_SetString(PyExc_TypeError, "error parsing protobuf");
- return NULL;
- }
- Py_RETURN_NONE;
-}
-
-static PyObject *msg_mergefromstring(PyObject *self, PyObject *args)
-{
- PyUpb_PbMsg *msg = Check_Message(self);
- char *strdata;
- size_t strlen;
- if(!PyArg_ParseTuple(args, BYTES_FORMAT, &strdata, &strlen))
- return NULL;
-
- if(upb_msg_parsestr(msg->ref.p.msg, strdata, strlen) != UPB_STATUS_OK) {
- /* TODO: better error than TypeError. */
- PyErr_SetString(PyExc_TypeError, "error parsing protobuf");
- return NULL;
- }
- Py_RETURN_NONE;
-}
-
-/* Commented-out methods are TODO. */
-static PyMethodDef msg_methods[] = {
- {"Clear", msg_clear, METH_NOARGS,
- "Erases all data from the ProtocolMessage, reseting fields to their defaults"
- },
- //{"CopyFrom", msg_copyfrom, METH_O,
- // "Copies data from another ProtocolMessage."
- //},
- //{"Encode", msg_encode, METH_NOARGS,
- // "Returns a string representing the ProtocolMessage."
- //},
- {"Equals", msg_equals, METH_O,
- "Returns true if the given ProtocolMessage has the same type and value."
- },
- {"IsInitialized", msg_isinitialized, METH_NOARGS,
- "Returns true iff all required fields have been set."
- },
- //{"Merge", msg_merge, METH_O,
- // "Merges data from the given Decoder."
- //},
- //{"MergeFrom", msg_mergefrom, METH_O,
- // "Merges data from another ProtocolMessage of the same type."
- //},
- {"MergeFromString", msg_mergefromstring, METH_VARARGS,
- "Merges data from the given string. Raises an exception if this does not "
- "result in the ProtocolMessage being initialized."
- },
- //{"Output", msg_output, METH_O,
- // "Writes the ProtocolMessage to the given encoder."
- //},
- //{"OutputUnchecked", msg_output, METH_O,
- // "Writes the ProtocolMessage to the given encoder, without checking "
- // "initialization"
- //},
- //{"Parse", msg_parse, METH_O,
- // "Parses data from the given Decoder."
- //},
- //{"ParseASCII", msg_parseascii, METH_VARARGS,
- // "Parses a string generated by ToASCII. Raises a ValueError if unknown "
- // "fields are encountered."
- //},
- //{"ParseASCIIIgnoreUnknown", msg_parseascii, METH_VARARGS,
- // "Parses a string generated by ToASCII. Ignores unknown fields."
- //},
- {"ParseFromString", msg_parsefromstring, METH_VARARGS,
- "Parses data from the given string. Raises an exception if this does not "
- "result in the ProtocolMessage being initialized."
- },
- //{"ToASCII", msg_toascii, METH_NOARGS,
- // "Returns the ProtocolMessage as a human-readable ASCII string."
- //},
- //{"ToCompactASCII", msg_tocompactascii, METH_NOARGS,
- // "Returns the ProtocolMessage as a human-readable ASCII string that uses "
- // "tag numbers instead of field names."
- //},
- //{"ToShortASCII", msg_toshortascii, METH_NOARGS,
- // "Returns the ProtocolMessage as a human-readable ASCII string, all on one
- // "line."
- //},
- //{"TryMerge", msg_trymerge, METH_O,
- // "Merges data from the given decoder.
- //}
- {NULL, NULL}
-};
-
-static bool starts_with(struct upb_string *str, struct upb_string *prefix,
- struct upb_string *out_str)
-{
- if(str->byte_len < prefix->byte_len) return false;
- if(memcmp(str->ptr, prefix->ptr, prefix->byte_len) == 0) {
- out_str->ptr = str->ptr + prefix->byte_len;
- out_str->byte_len = str->byte_len - prefix->byte_len;
- return true;
- } else {
- return false;
- }
-}
-
-static bool ends_with(struct upb_string *str, struct upb_string *suffix,
- struct upb_string *out_str)
-{
- if(str->byte_len < suffix->byte_len) return false;
- if(memcmp(str->ptr + str->byte_len - suffix->byte_len, suffix->ptr, suffix->byte_len) == 0) {
- out_str->ptr = str->ptr;
- out_str->byte_len = str->byte_len - suffix->byte_len;
- return true;
- } else {
- return false;
- }
-}
-
-PyObject *PyUpb_NewPbBoundFieldOp(PyUpb_PbMsg *msgobj, struct upb_fielddef *f,
- PyUpb_PbBoundFieldOpCode code)
-{
- /* Type check that this operation on a field of this type makes sense. */
- if(upb_isarray(f)) {
- switch(code) {
- case OP_HAS:
- case OP_SET:
- case OP_MUTABLE:
- return NULL;
- default: break;
- }
- } else {
- if(upb_issubmsg(f)) {
- switch(code) {
- case OP_SET:
- case OP_SIZE:
- case OP_LIST:
- case OP_ADD:
- return NULL;
- default: break;
- }
- } else {
- switch(code) {
- case OP_MUTABLE:
- case OP_SIZE:
- case OP_LIST:
- case OP_ADD:
- return NULL;
- default: break;
- }
- }
- }
-
- PyUpb_PbBoundFieldOp *op =
- (void*)PyUpb_PbBoundFieldOpType.tp_alloc(&PyUpb_PbBoundFieldOpType, 0);
- op->msg = msgobj;
- op->f = f;
- op->code = code;
- Py_INCREF(op->msg);
- return (PyObject*)op;
-}
-
-PyObject* msg_getattro(PyObject *obj, PyObject *attr_name)
-{
- /* Each protobuf field results in a set of four methods for a scalar or five
- * methods for an array. To avoid putting 4f entries in our type dict, we
- * dynamically scan the method to see if it is of these forms, and if so,
- * look it up in the hash table that upb already keeps.
- *
- * If these repeated comparisons showed up as being a hot spot in a profile,
- * there are several ways this dispatch could be optimized. */
- static struct upb_string set = {.ptr = "set_", .byte_len = 4};
- static struct upb_string has = {.ptr = "has_", .byte_len = 4};
- static struct upb_string clear = {.ptr = "clear_", .byte_len = 6};
- static struct upb_string size = {.ptr = "_size", .byte_len = 5};
- static struct upb_string mutable = {.ptr = "mutable_", .byte_len = 8};
- static struct upb_string add = {.ptr = "add_", .byte_len = 4};
- static struct upb_string list = {.ptr = "_list", .byte_len = 5};
-
- struct upb_string str;
- Py_ssize_t len;
- PyString_AsStringAndSize(attr_name, &str.ptr, &len);
- if(len > UINT32_MAX) {
- PyErr_SetString(PyExc_TypeError,
- "Wow, that's a long attribute name you've got there.");
- return NULL;
- }
- str.byte_len = (uint32_t)len;
- PyUpb_PbMsg *msgobj = Check_Message(obj);
- struct upb_msgdef *def = msgobj->ref.p.msg->def;
-
- /* This can be a field reference iff the first letter is lowercase, because
- * generic methods (eg. IsInitialized()) all start with uppercase. */
- if(islower(str.ptr[0])) {
- PyUpb_PbBoundFieldOpCode opcode;
- struct upb_string field_name;
- if(starts_with(&str, &has, &field_name))
- opcode = OP_HAS;
- else if(starts_with(&str, &set, &field_name))
- opcode = OP_SET;
- else if(starts_with(&str, &mutable, &field_name))
- opcode = OP_MUTABLE;
- else if(ends_with(&str, &size, &field_name))
- opcode = OP_SIZE;
- else if(ends_with(&str, &list, &field_name))
- opcode = OP_LIST;
- else if(starts_with(&str, &add, &field_name))
- opcode = OP_ADD;
- else if(starts_with(&str, &clear, &field_name))
- opcode = OP_CLEAR;
- else {
- /* Could be a plain field reference (eg. obj.field(i)). */
- opcode = OP_GET;
- field_name = str;
- }
- struct upb_fielddef *f = upb_msg_fieldbyname(def, &field_name);
- if(f) {
- PyObject *op = PyUpb_NewPbBoundFieldOp(msgobj, f, opcode);
- if(op) return op;
- }
- }
-
- /* Fall back on regular attribute lookup. */
- return PyObject_GenericGetAttr(obj, attr_name);
-}
-
-static void msg_dealloc(PyObject *obj)
-{
- PyUpb_PbMsg *msg = (void*)obj;
- upb_mm_release(&msg->ref);
- Py_DECREF(msg->def);
- obj->ob_type->tp_free(obj);
-}
-
-static PyTypeObject PyUpb_PbMsgType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "upb.pb.Message", /* tp_name */
- sizeof(PyUpb_PbMsg), /* tp_basicsize */
- 0, /* tp_itemsize */
- msg_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr (TODO) */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- msg_getattro, /* tp_getattro */
- 0, /* Not allowed. */ /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse (TODO) */
- 0, /* tp_clear (TODO) */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- msg_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 */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* Can't be created from Python. */ /* tp_new */
- 0, /* tp_free */
-};
-
-/* upb.pb.MessageCreator ******************************************************/
-
-static PyObject *creator_call(PyObject *callable, PyObject *args, PyObject *kw)
-{
- PyUpb_PbMsgCreator *creator = Check_MsgCreator(callable);
- return MMREF_TO_PYOBJ(upb_mm_newmsg_ref(creator->def->def, &pymm));
-}
-
-static PyObject *creator_repr(PyObject *obj)
-{
- PyUpb_PbMsgCreator *creator = Check_MsgCreator(obj);
- struct upb_string *name = creator->def->def->descriptor->name;
- /* Need to get a NULL-terminated copy of name since PyString_FromFormat
- * doesn't support ptr+len. */
- PyObject *nameobj = PyString_FromStringAndSize(name->ptr, name->byte_len);
- PyObject *ret = PyString_FromFormat("<upb.pb.MessageCreator for '%s'>",
- PyString_AS_STRING(nameobj));
- Py_DECREF(nameobj);
- return ret;
-}
-
-static void creator_dealloc(PyObject *obj)
-{
- PyUpb_PbMsgCreator *creator = (void*)obj;
- Py_DECREF(creator->def);
- obj->ob_type->tp_free(obj);
-}
-
-static PyObject *creator_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyUpb_PbMsgCreator *creator = (void*)type->tp_alloc(type, 0);
- PyUpb_MsgDef *def;
- if(!PyArg_ParseTuple(args, "O!", &PyUpb_MsgDefType, &def)) return NULL;
- creator->def = def;
- Py_INCREF(creator->def);
- return (PyObject*)creator;
-}
-
-static PyTypeObject PyUpb_PbMsgCreatorType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "upb.pb.MessageCreator", /* tp_name */
- sizeof(PyUpb_PbMsgCreator), /* tp_basicsize */
- 0, /* tp_itemsize */
- creator_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- creator_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- creator_call, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* 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 */
- 0, /* tp_init */
- 0, /* tp_alloc */
- creator_new, /* tp_new */
- 0, /* tp_free */
-};
-
-/* upb.pb module **************************************************************/
-
-static PyMethodDef methods[] = {
- {NULL, NULL}
-};
-
-PyMODINIT_FUNC
-initpb(void)
-{
- if(PyType_Ready(&PyUpb_PbBoundFieldOpType) < 0) return;
- if(PyType_Ready(&PyUpb_PbMsgType) < 0) return;
- if(PyType_Ready(&PyUpb_PbMsgCreatorType) < 0) return;
-
- /* PyModule_AddObject steals a reference. These objects are statically
- * allocated and must not be deleted, so we increment their refcount. */
- Py_INCREF(&PyUpb_PbBoundFieldOpType);
- Py_INCREF(&PyUpb_PbMsgType);
- Py_INCREF(&PyUpb_PbMsgCreatorType);
-
- PyObject *mod = Py_InitModule("upb.cext.pb", methods);
- PyModule_AddObject(mod, "BoundFieldOp", (PyObject*)&PyUpb_PbBoundFieldOpType);
- PyModule_AddObject(mod, "Message", (PyObject*)&PyUpb_PbMsgType);
- PyModule_AddObject(mod, "MessageCreator", (PyObject*)&PyUpb_PbMsgCreatorType);
-}
diff --git a/lang_ext/python/setup.py b/lang_ext/python/setup.py
index ec34e7d..8abaff8 100644
--- a/lang_ext/python/setup.py
+++ b/lang_ext/python/setup.py
@@ -3,12 +3,10 @@ from distutils.core import setup, Extension
setup(name='upb',
version='0.1',
ext_modules=[
- Extension('upb.cext', ['definition.c', 'pb.c', 'cext.c'],
- include_dirs=['../../src', '../../descriptor'],
- define_macros=[("UPB_USE_PTHREADS", 1),
- ("UPB_UNALIGNED_READS_OK", 1),
- ("UPB_THREAD_UNSAFE", 1)],
- library_dirs=['../../src'],
+ Extension('upb.__init__', ['upb.c'],
+ include_dirs=['../../'],
+ define_macros=[("UPB_UNALIGNED_READS_OK", 1)],
+ library_dirs=['../../upb'],
libraries=['upb_pic'],
),
],
diff --git a/lang_ext/python/test.py b/lang_ext/python/test.py
new file mode 100644
index 0000000..df152da
--- /dev/null
+++ b/lang_ext/python/test.py
@@ -0,0 +1,14 @@
+
+import upb
+import unittest
+
+class TestFieldDef(unittest.TestCase):
+ def test_construction(self):
+ fielddef1 = upb.FieldDef()
+ self.assertTrue(fielddef1 is not None)
+ fielddef2 = upb.FieldDef(number=1, name="field1", label=2, type=3)
+ self.assertTrue(fielddef2 is not None)
+ self.assertTrue(id(fielddef1) != id(fielddef2))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/lang_ext/python/upb.c b/lang_ext/python/upb.c
new file mode 100644
index 0000000..9a48401
--- /dev/null
+++ b/lang_ext/python/upb.c
@@ -0,0 +1,190 @@
+/*
+ * 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 <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;
+
+
+/* PyUpb_FieldDef *************************************************************/
+
+typedef struct {
+ PyObject_HEAD;
+ upb_fielddef *field;
+} PyUpb_FieldDef;
+
+static PyTypeObject PyUpb_FieldDefType;
+
+#define Check_FieldDef(obj, badret) \
+ (void*)obj; do { \
+ if(!PyObject_TypeCheck(obj, &PyUpb_FieldDefType)) { \
+ PyErr_SetString(PyExc_TypeError, "must be a upb.FieldDef"); \
+ return badret; \
+ } \
+ } while(0)
+
+static void PyUpb_FieldDef_dealloc(PyObject *obj) {
+ PyUpb_FieldDef *f = (void*)obj;
+ upb_fielddef_unref(f->field);
+ obj->ob_type->tp_free(obj);
+}
+
+static PyObject* PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) {
+ PyUpb_FieldDef *f = Check_FieldDef(obj, NULL);
+ const char *name = PyString_AsString(attr_name);
+ if (streql(name, "name")) {
+ return PyString_FromString(upb_fielddef_name(f->field));
+ } else if (streql(name, "number")) {
+ return PyInt_FromLong(upb_fielddef_number(f->field));
+ } else if (streql(name, "type")) {
+ return PyInt_FromLong(upb_fielddef_type(f->field));
+ } else if (streql(name, "label")) {
+ return PyInt_FromLong(upb_fielddef_label(f->field));
+ } 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) {
+ PyUpb_FieldDef *f = Check_FieldDef(o, -1);
+ const char *field = PyString_AsString(key);
+ if (!upb_fielddef_ismutable(f->field))
+ return PyUpb_ErrorInt("fielddef is not mutable.");
+ if (streql(field, "name")) {
+ const char *name = PyString_AsString(val);
+ if (!name || !upb_fielddef_setname(f->field, 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->field, 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->field, 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->field, 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->field, 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 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 PyObject *PyUpb_FieldDef_new(PyTypeObject *subtype,
+ PyObject *args, PyObject *kwds) {
+ PyUpb_FieldDef *f = (PyUpb_FieldDef*)subtype->tp_alloc(subtype, 0);
+ f->field = upb_fielddef_new();
+ return (PyObject*)f;
+}
+
+static PyTypeObject PyUpb_FieldDefType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "upb.FieldDef", /* tp_name */
+ sizeof(PyUpb_FieldDef), /* 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 */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* 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 */
+};
+
+static PyMethodDef methods[] = {
+ {NULL, NULL}
+};
+
+PyMODINIT_FUNC initupb(void) {
+ PyObject *mod = Py_InitModule("upb", methods);
+ if (PyType_Ready(&PyUpb_FieldDefType) < 0) return;
+
+ // PyModule_AddObject steals a ref, but our object is statically allocated
+ // and must not be deleted.
+ Py_INCREF(&PyUpb_FieldDefType);
+
+ PyModule_AddObject(mod, "FieldDef", (PyObject*)&PyUpb_FieldDefType);
+}
diff --git a/lang_ext/python/upb/definition.py b/lang_ext/python/upb/definition.py
deleted file mode 100644
index f03a2dc..0000000
--- a/lang_ext/python/upb/definition.py
+++ /dev/null
@@ -1 +0,0 @@
-from upb.cext.definition import *
diff --git a/lang_ext/python/upb/pb.py b/lang_ext/python/upb/pb.py
deleted file mode 100644
index 6b1654a..0000000
--- a/lang_ext/python/upb/pb.py
+++ /dev/null
@@ -1 +0,0 @@
-from upb.cext.pb import *
diff --git a/upb/def.h b/upb/def.h
index 8800712..9571773 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -95,7 +95,7 @@ typedef struct _upb_fielddef {
struct _upb_accessor_vtbl *accessor;
} upb_fielddef;
-upb_fielddef *upb_fielddef_new();
+upb_fielddef *upb_fielddef_new(void);
void upb_fielddef_ref(upb_fielddef *f);
void upb_fielddef_unref(upb_fielddef *f);
upb_fielddef *upb_fielddef_dup(upb_fielddef *f);
@@ -186,7 +186,7 @@ typedef struct {
upb_fielddef *f;
} upb_ntof_ent;
-upb_msgdef *upb_msgdef_new();
+upb_msgdef *upb_msgdef_new(void);
INLINE void upb_msgdef_unref(upb_msgdef *md) { upb_def_unref(UPB_UPCAST(md)); }
INLINE void upb_msgdef_ref(upb_msgdef *md) { upb_def_ref(UPB_UPCAST(md)); }
@@ -284,7 +284,7 @@ typedef struct {
char *str;
} upb_iton_ent;
-upb_enumdef *upb_enumdef_new();
+upb_enumdef *upb_enumdef_new(void);
INLINE void upb_enumdef_ref(upb_enumdef *e) { upb_def_ref(UPB_UPCAST(e)); }
INLINE void upb_enumdef_unref(upb_enumdef *e) { upb_def_unref(UPB_UPCAST(e)); }
upb_enumdef *upb_enumdef_dup(upb_enumdef *e);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback