]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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 | #include <Python.h> | |
21 | #include "types.h" | |
22 | #include "binary.h" | |
23 | #include "compact.h" | |
24 | #include <limits> | |
25 | #include <stdint.h> | |
26 | ||
27 | // TODO(dreiss): defval appears to be unused. Look into removing it. | |
28 | // TODO(dreiss): Make parse_spec_args recursive, and cache the output | |
29 | // permanently in the object. (Malloc and orphan.) | |
30 | // TODO(dreiss): Why do we need cStringIO for reading, why not just char*? | |
31 | // Can cStringIO let us work with a BufferedTransport? | |
32 | // TODO(dreiss): Don't ignore the rv from cwrite (maybe). | |
33 | ||
34 | // Doing a benchmark shows that interning actually makes a difference, amazingly. | |
35 | ||
36 | /** Pointer to interned string to speed up attribute lookup. */ | |
37 | PyObject* INTERN_STRING(TFrozenDict); | |
38 | PyObject* INTERN_STRING(cstringio_buf); | |
39 | PyObject* INTERN_STRING(cstringio_refill); | |
40 | static PyObject* INTERN_STRING(string_length_limit); | |
41 | static PyObject* INTERN_STRING(container_length_limit); | |
42 | static PyObject* INTERN_STRING(trans); | |
43 | ||
44 | namespace apache { | |
45 | namespace thrift { | |
46 | namespace py { | |
47 | ||
48 | template <typename T> | |
49 | static PyObject* encode_impl(PyObject* args) { | |
50 | if (!args) | |
51 | return NULL; | |
52 | ||
53 | PyObject* enc_obj = NULL; | |
54 | PyObject* type_args = NULL; | |
55 | if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) { | |
56 | return NULL; | |
57 | } | |
58 | if (!enc_obj || !type_args) { | |
59 | return NULL; | |
60 | } | |
61 | ||
62 | T protocol; | |
63 | if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) { | |
64 | return NULL; | |
65 | } | |
66 | ||
67 | return protocol.getEncodedValue(); | |
68 | } | |
69 | ||
70 | static inline long as_long_then_delete(PyObject* value, long default_value) { | |
71 | ScopedPyObject scope(value); | |
72 | long v = PyInt_AsLong(value); | |
73 | if (INT_CONV_ERROR_OCCURRED(v)) { | |
74 | PyErr_Clear(); | |
75 | return default_value; | |
76 | } | |
77 | return v; | |
78 | } | |
79 | ||
80 | template <typename T> | |
81 | static PyObject* decode_impl(PyObject* args) { | |
82 | PyObject* output_obj = NULL; | |
83 | PyObject* oprot = NULL; | |
84 | PyObject* typeargs = NULL; | |
85 | if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) { | |
86 | return NULL; | |
87 | } | |
88 | ||
89 | T protocol; | |
90 | int32_t default_limit = (std::numeric_limits<int32_t>::max)(); | |
91 | protocol.setStringLengthLimit( | |
92 | as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)), | |
93 | default_limit)); | |
94 | protocol.setContainerLengthLimit( | |
95 | as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)), | |
96 | default_limit)); | |
97 | ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans))); | |
98 | if (!transport) { | |
99 | return NULL; | |
100 | } | |
101 | ||
102 | StructTypeArgs parsedargs; | |
103 | if (!parse_struct_args(&parsedargs, typeargs)) { | |
104 | return NULL; | |
105 | } | |
106 | ||
107 | if (!protocol.prepareDecodeBufferFromTransport(transport.get())) { | |
108 | return NULL; | |
109 | } | |
110 | ||
111 | return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec); | |
112 | } | |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | using namespace apache::thrift::py; | |
118 | ||
119 | /* -- PYTHON MODULE SETUP STUFF --- */ | |
120 | ||
121 | extern "C" { | |
122 | ||
123 | static PyObject* encode_binary(PyObject*, PyObject* args) { | |
124 | return encode_impl<BinaryProtocol>(args); | |
125 | } | |
126 | ||
127 | static PyObject* decode_binary(PyObject*, PyObject* args) { | |
128 | return decode_impl<BinaryProtocol>(args); | |
129 | } | |
130 | ||
131 | static PyObject* encode_compact(PyObject*, PyObject* args) { | |
132 | return encode_impl<CompactProtocol>(args); | |
133 | } | |
134 | ||
135 | static PyObject* decode_compact(PyObject*, PyObject* args) { | |
136 | return decode_impl<CompactProtocol>(args); | |
137 | } | |
138 | ||
139 | static PyMethodDef ThriftFastBinaryMethods[] = { | |
140 | {"encode_binary", encode_binary, METH_VARARGS, ""}, | |
141 | {"decode_binary", decode_binary, METH_VARARGS, ""}, | |
142 | {"encode_compact", encode_compact, METH_VARARGS, ""}, | |
143 | {"decode_compact", decode_compact, METH_VARARGS, ""}, | |
144 | {NULL, NULL, 0, NULL} /* Sentinel */ | |
145 | }; | |
146 | ||
147 | #if PY_MAJOR_VERSION >= 3 | |
148 | ||
149 | static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT, | |
150 | "thrift.protocol.fastbinary", | |
151 | NULL, | |
152 | 0, | |
153 | ThriftFastBinaryMethods, | |
154 | NULL, | |
155 | NULL, | |
156 | NULL, | |
157 | NULL}; | |
158 | ||
159 | #define INITERROR return NULL; | |
160 | ||
161 | PyObject* PyInit_fastbinary() { | |
162 | ||
163 | #else | |
164 | ||
165 | #define INITERROR return; | |
166 | ||
167 | void initfastbinary() { | |
168 | ||
169 | PycString_IMPORT; | |
170 | if (PycStringIO == NULL) | |
171 | INITERROR | |
172 | ||
173 | #endif | |
174 | ||
175 | #define INIT_INTERN_STRING(value) \ | |
176 | do { \ | |
177 | INTERN_STRING(value) = PyString_InternFromString(#value); \ | |
178 | if (!INTERN_STRING(value)) \ | |
179 | INITERROR \ | |
180 | } while (0) | |
181 | ||
182 | INIT_INTERN_STRING(TFrozenDict); | |
183 | INIT_INTERN_STRING(cstringio_buf); | |
184 | INIT_INTERN_STRING(cstringio_refill); | |
185 | INIT_INTERN_STRING(string_length_limit); | |
186 | INIT_INTERN_STRING(container_length_limit); | |
187 | INIT_INTERN_STRING(trans); | |
188 | #undef INIT_INTERN_STRING | |
189 | ||
190 | PyObject* module = | |
191 | #if PY_MAJOR_VERSION >= 3 | |
192 | PyModule_Create(&ThriftFastBinaryDef); | |
193 | #else | |
194 | Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods); | |
195 | #endif | |
196 | if (module == NULL) | |
197 | INITERROR; | |
198 | ||
199 | #if PY_MAJOR_VERSION >= 3 | |
200 | return module; | |
201 | #endif | |
202 | } | |
203 | } |