1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef THRIFT_PY_TYPES_H
21 #define THRIFT_PY_TYPES_H
22 
23 #include <Python.h>
24 
25 #ifdef _MSC_VER
26 #define __STDC_FORMAT_MACROS
27 #define __STDC_LIMIT_MACROS
28 #endif
29 #include <stdint.h>
30 
31 #if PY_MAJOR_VERSION >= 3
32 
33 #include <vector>
34 
35 // TODO: better macros
36 #define PyInt_AsLong(v) PyLong_AsLong(v)
37 #define PyInt_FromLong(v) PyLong_FromLong(v)
38 
39 #define PyString_InternFromString(v) PyUnicode_InternFromString(v)
40 
41 #endif
42 
43 #define INTERN_STRING(value) _intern_##value
44 
45 #define INT_CONV_ERROR_OCCURRED(v) (((v) == -1) && PyErr_Occurred())
46 
47 extern "C" {
48 extern PyObject* INTERN_STRING(TFrozenDict);
49 extern PyObject* INTERN_STRING(cstringio_buf);
50 extern PyObject* INTERN_STRING(cstringio_refill);
51 }
52 
53 namespace apache {
54 namespace thrift {
55 namespace py {
56 
57 extern PyObject* ThriftModule;
58 
59 // Stolen out of TProtocol.h.
60 // It would be a huge pain to have both get this from one place.
61 enum TType {
62   T_INVALID = -1,
63   T_STOP = 0,
64   T_VOID = 1,
65   T_BOOL = 2,
66   T_BYTE = 3,
67   T_I08 = 3,
68   T_I16 = 6,
69   T_I32 = 8,
70   T_U64 = 9,
71   T_I64 = 10,
72   T_DOUBLE = 4,
73   T_STRING = 11,
74   T_UTF7 = 11,
75   T_STRUCT = 12,
76   T_MAP = 13,
77   T_SET = 14,
78   T_LIST = 15,
79   T_UTF8 = 16,
80   T_UTF16 = 17
81 };
82 
83 // replace with unique_ptr when we're OK with C++11
84 class ScopedPyObject {
85 public:
ScopedPyObject()86   ScopedPyObject() : obj_(nullptr) {}
ScopedPyObject(PyObject * py_object)87   explicit ScopedPyObject(PyObject* py_object) : obj_(py_object) {}
~ScopedPyObject()88   ~ScopedPyObject() {
89     if (obj_)
90       Py_DECREF(obj_);
91   }
get()92   PyObject* get() throw() { return obj_; }
93   operator bool() { return obj_; }
reset(PyObject * py_object)94   void reset(PyObject* py_object) throw() {
95     if (obj_)
96       Py_DECREF(obj_);
97     obj_ = py_object;
98   }
release()99   PyObject* release() throw() {
100     PyObject* tmp = obj_;
101     obj_ = nullptr;
102     return tmp;
103   }
swap(ScopedPyObject & other)104   void swap(ScopedPyObject& other) throw() {
105     ScopedPyObject tmp(other.release());
106     other.reset(release());
107     reset(tmp.release());
108   }
109 
110 private:
ScopedPyObject(const ScopedPyObject &)111   ScopedPyObject(const ScopedPyObject&) {}
112   ScopedPyObject& operator=(const ScopedPyObject&) { return *this; }
113 
114   PyObject* obj_;
115 };
116 
117 /**
118  * A cache of the two key attributes of a CReadableTransport,
119  * so we don't have to keep calling PyObject_GetAttr.
120  */
121 struct DecodeBuffer {
122   ScopedPyObject stringiobuf;
123   ScopedPyObject refill_callable;
124 };
125 
126 #if PY_MAJOR_VERSION < 3
127 extern char refill_signature[3];
128 typedef PyObject EncodeBuffer;
129 #else
130 extern const char* refill_signature;
131 struct EncodeBuffer {
132   std::vector<char> buf;
133   size_t pos;
134 };
135 #endif
136 
137 /**
138  * A cache of the spec_args for a set or list,
139  * so we don't have to keep calling PyTuple_GET_ITEM.
140  */
141 struct SetListTypeArgs {
142   TType element_type;
143   PyObject* typeargs;
144   bool immutable;
145 };
146 
147 /**
148  * A cache of the spec_args for a map,
149  * so we don't have to keep calling PyTuple_GET_ITEM.
150  */
151 struct MapTypeArgs {
152   TType ktag;
153   TType vtag;
154   PyObject* ktypeargs;
155   PyObject* vtypeargs;
156   bool immutable;
157 };
158 
159 /**
160  * A cache of the spec_args for a struct,
161  * so we don't have to keep calling PyTuple_GET_ITEM.
162  */
163 struct StructTypeArgs {
164   PyObject* klass;
165   PyObject* spec;
166   bool immutable;
167 };
168 
169 /**
170  * A cache of the item spec from a struct specification,
171  * so we don't have to keep calling PyTuple_GET_ITEM.
172  */
173 struct StructItemSpec {
174   int tag;
175   TType type;
176   PyObject* attrname;
177   PyObject* typeargs;
178   PyObject* defval;
179 };
180 
181 bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs);
182 
183 bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs);
184 
185 bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs);
186 
187 bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple);
188 }
189 }
190 }
191 
192 #endif // THRIFT_PY_TYPES_H
193