blob: 79deda8fd73fd3287a0db5683e214e3b9eab4636 [file] [log] [blame]
Roger Meierf4eec7a2011-09-11 18:16:21 +00001#
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
David Reissabafd792010-09-27 17:28:15 +000020from TProtocol import *
21from struct import pack, unpack
22
23__all__ = ['TCompactProtocol', 'TCompactProtocolFactory']
24
25CLEAR = 0
26FIELD_WRITE = 1
27VALUE_WRITE = 2
28CONTAINER_WRITE = 3
29BOOL_WRITE = 4
30FIELD_READ = 5
31CONTAINER_READ = 6
32VALUE_READ = 7
33BOOL_READ = 8
34
Bryan Duxbury69720412012-01-03 17:32:30 +000035
David Reissabafd792010-09-27 17:28:15 +000036def make_helper(v_from, container):
37 def helper(func):
38 def nested(self, *args, **kwargs):
39 assert self.state in (v_from, container), (self.state, v_from, container)
40 return func(self, *args, **kwargs)
41 return nested
42 return helper
43writer = make_helper(VALUE_WRITE, CONTAINER_WRITE)
44reader = make_helper(VALUE_READ, CONTAINER_READ)
45
Bryan Duxbury69720412012-01-03 17:32:30 +000046
David Reissabafd792010-09-27 17:28:15 +000047def makeZigZag(n, bits):
48 return (n << 1) ^ (n >> (bits - 1))
49
Bryan Duxbury69720412012-01-03 17:32:30 +000050
David Reissabafd792010-09-27 17:28:15 +000051def fromZigZag(n):
52 return (n >> 1) ^ -(n & 1)
53
Bryan Duxbury69720412012-01-03 17:32:30 +000054
David Reissabafd792010-09-27 17:28:15 +000055def writeVarint(trans, n):
56 out = []
57 while True:
58 if n & ~0x7f == 0:
59 out.append(n)
60 break
61 else:
62 out.append((n & 0xff) | 0x80)
63 n = n >> 7
64 trans.write(''.join(map(chr, out)))
65
Bryan Duxbury69720412012-01-03 17:32:30 +000066
David Reissabafd792010-09-27 17:28:15 +000067def readVarint(trans):
68 result = 0
69 shift = 0
70 while True:
71 x = trans.readAll(1)
72 byte = ord(x)
73 result |= (byte & 0x7f) << shift
74 if byte >> 7 == 0:
75 return result
76 shift += 7
77
Bryan Duxbury69720412012-01-03 17:32:30 +000078
David Reissabafd792010-09-27 17:28:15 +000079class CompactType:
Bryan Duxburydf4cffd2011-03-15 17:16:09 +000080 STOP = 0x00
81 TRUE = 0x01
82 FALSE = 0x02
David Reissabafd792010-09-27 17:28:15 +000083 BYTE = 0x03
84 I16 = 0x04
85 I32 = 0x05
86 I64 = 0x06
87 DOUBLE = 0x07
88 BINARY = 0x08
89 LIST = 0x09
90 SET = 0x0A
91 MAP = 0x0B
92 STRUCT = 0x0C
93
Bryan Duxburydf4cffd2011-03-15 17:16:09 +000094CTYPES = {TType.STOP: CompactType.STOP,
Bryan Duxbury69720412012-01-03 17:32:30 +000095 TType.BOOL: CompactType.TRUE, # used for collection
David Reissabafd792010-09-27 17:28:15 +000096 TType.BYTE: CompactType.BYTE,
97 TType.I16: CompactType.I16,
98 TType.I32: CompactType.I32,
99 TType.I64: CompactType.I64,
100 TType.DOUBLE: CompactType.DOUBLE,
101 TType.STRING: CompactType.BINARY,
102 TType.STRUCT: CompactType.STRUCT,
103 TType.LIST: CompactType.LIST,
104 TType.SET: CompactType.SET,
Bryan Duxburydf4cffd2011-03-15 17:16:09 +0000105 TType.MAP: CompactType.MAP
David Reissabafd792010-09-27 17:28:15 +0000106 }
107
108TTYPES = {}
109for k, v in CTYPES.items():
110 TTYPES[v] = k
111TTYPES[CompactType.FALSE] = TType.BOOL
112del k
113del v
114
Bryan Duxbury69720412012-01-03 17:32:30 +0000115
David Reissabafd792010-09-27 17:28:15 +0000116class TCompactProtocol(TProtocolBase):
Bryan Duxbury69720412012-01-03 17:32:30 +0000117 """Compact implementation of the Thrift protocol driver."""
David Reissabafd792010-09-27 17:28:15 +0000118
119 PROTOCOL_ID = 0x82
120 VERSION = 1
121 VERSION_MASK = 0x1f
122 TYPE_MASK = 0xe0
Jens Geyera86886e2014-09-17 22:25:48 +0200123 TYPE_BITS = 0x07
David Reissabafd792010-09-27 17:28:15 +0000124 TYPE_SHIFT_AMOUNT = 5
125
126 def __init__(self, trans):
127 TProtocolBase.__init__(self, trans)
128 self.state = CLEAR
129 self.__last_fid = 0
130 self.__bool_fid = None
131 self.__bool_value = None
132 self.__structs = []
133 self.__containers = []
134
135 def __writeVarint(self, n):
136 writeVarint(self.trans, n)
137
138 def writeMessageBegin(self, name, type, seqid):
139 assert self.state == CLEAR
140 self.__writeUByte(self.PROTOCOL_ID)
141 self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT))
142 self.__writeVarint(seqid)
143 self.__writeString(name)
144 self.state = VALUE_WRITE
145
146 def writeMessageEnd(self):
147 assert self.state == VALUE_WRITE
148 self.state = CLEAR
149
150 def writeStructBegin(self, name):
151 assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state
152 self.__structs.append((self.state, self.__last_fid))
153 self.state = FIELD_WRITE
154 self.__last_fid = 0
155
156 def writeStructEnd(self):
157 assert self.state == FIELD_WRITE
158 self.state, self.__last_fid = self.__structs.pop()
159
160 def writeFieldStop(self):
161 self.__writeByte(0)
162
163 def __writeFieldHeader(self, type, fid):
164 delta = fid - self.__last_fid
165 if 0 < delta <= 15:
166 self.__writeUByte(delta << 4 | type)
167 else:
168 self.__writeByte(type)
169 self.__writeI16(fid)
170 self.__last_fid = fid
171
172 def writeFieldBegin(self, name, type, fid):
173 assert self.state == FIELD_WRITE, self.state
174 if type == TType.BOOL:
175 self.state = BOOL_WRITE
176 self.__bool_fid = fid
177 else:
178 self.state = VALUE_WRITE
179 self.__writeFieldHeader(CTYPES[type], fid)
180
181 def writeFieldEnd(self):
182 assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state
183 self.state = FIELD_WRITE
184
185 def __writeUByte(self, byte):
186 self.trans.write(pack('!B', byte))
187
188 def __writeByte(self, byte):
189 self.trans.write(pack('!b', byte))
190
191 def __writeI16(self, i16):
192 self.__writeVarint(makeZigZag(i16, 16))
193
194 def __writeSize(self, i32):
195 self.__writeVarint(i32)
196
197 def writeCollectionBegin(self, etype, size):
198 assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
199 if size <= 14:
200 self.__writeUByte(size << 4 | CTYPES[etype])
201 else:
202 self.__writeUByte(0xf0 | CTYPES[etype])
203 self.__writeSize(size)
204 self.__containers.append(self.state)
205 self.state = CONTAINER_WRITE
206 writeSetBegin = writeCollectionBegin
207 writeListBegin = writeCollectionBegin
208
209 def writeMapBegin(self, ktype, vtype, size):
210 assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
211 if size == 0:
212 self.__writeByte(0)
213 else:
214 self.__writeSize(size)
215 self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype])
216 self.__containers.append(self.state)
217 self.state = CONTAINER_WRITE
218
219 def writeCollectionEnd(self):
220 assert self.state == CONTAINER_WRITE, self.state
221 self.state = self.__containers.pop()
222 writeMapEnd = writeCollectionEnd
223 writeSetEnd = writeCollectionEnd
224 writeListEnd = writeCollectionEnd
225
226 def writeBool(self, bool):
227 if self.state == BOOL_WRITE:
Bryan Duxbury69720412012-01-03 17:32:30 +0000228 if bool:
229 ctype = CompactType.TRUE
230 else:
231 ctype = CompactType.FALSE
232 self.__writeFieldHeader(ctype, self.__bool_fid)
David Reissabafd792010-09-27 17:28:15 +0000233 elif self.state == CONTAINER_WRITE:
Bryan Duxbury69720412012-01-03 17:32:30 +0000234 if bool:
235 self.__writeByte(CompactType.TRUE)
236 else:
237 self.__writeByte(CompactType.FALSE)
David Reissabafd792010-09-27 17:28:15 +0000238 else:
Bryan Duxbury69720412012-01-03 17:32:30 +0000239 raise AssertionError("Invalid state in compact protocol")
David Reissabafd792010-09-27 17:28:15 +0000240
241 writeByte = writer(__writeByte)
242 writeI16 = writer(__writeI16)
243
244 @writer
245 def writeI32(self, i32):
246 self.__writeVarint(makeZigZag(i32, 32))
247
248 @writer
249 def writeI64(self, i64):
250 self.__writeVarint(makeZigZag(i64, 64))
251
252 @writer
253 def writeDouble(self, dub):
Roger Meier8c691fa2013-11-05 04:54:33 +0100254 self.trans.write(pack('<d', dub))
David Reissabafd792010-09-27 17:28:15 +0000255
256 def __writeString(self, s):
257 self.__writeSize(len(s))
258 self.trans.write(s)
259 writeString = writer(__writeString)
260
261 def readFieldBegin(self):
262 assert self.state == FIELD_READ, self.state
263 type = self.__readUByte()
264 if type & 0x0f == TType.STOP:
265 return (None, 0, 0)
266 delta = type >> 4
267 if delta == 0:
268 fid = self.__readI16()
269 else:
270 fid = self.__last_fid + delta
271 self.__last_fid = fid
272 type = type & 0x0f
273 if type == CompactType.TRUE:
274 self.state = BOOL_READ
275 self.__bool_value = True
276 elif type == CompactType.FALSE:
277 self.state = BOOL_READ
278 self.__bool_value = False
279 else:
280 self.state = VALUE_READ
281 return (None, self.__getTType(type), fid)
282
283 def readFieldEnd(self):
284 assert self.state in (VALUE_READ, BOOL_READ), self.state
285 self.state = FIELD_READ
286
287 def __readUByte(self):
288 result, = unpack('!B', self.trans.readAll(1))
289 return result
290
291 def __readByte(self):
292 result, = unpack('!b', self.trans.readAll(1))
293 return result
294
295 def __readVarint(self):
296 return readVarint(self.trans)
297
298 def __readZigZag(self):
299 return fromZigZag(self.__readVarint())
300
301 def __readSize(self):
302 result = self.__readVarint()
303 if result < 0:
304 raise TException("Length < 0")
305 return result
306
307 def readMessageBegin(self):
308 assert self.state == CLEAR
309 proto_id = self.__readUByte()
310 if proto_id != self.PROTOCOL_ID:
311 raise TProtocolException(TProtocolException.BAD_VERSION,
312 'Bad protocol id in the message: %d' % proto_id)
313 ver_type = self.__readUByte()
Jens Geyera86886e2014-09-17 22:25:48 +0200314 type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS
David Reissabafd792010-09-27 17:28:15 +0000315 version = ver_type & self.VERSION_MASK
316 if version != self.VERSION:
317 raise TProtocolException(TProtocolException.BAD_VERSION,
318 'Bad version: %d (expect %d)' % (version, self.VERSION))
319 seqid = self.__readVarint()
320 name = self.__readString()
321 return (name, type, seqid)
322
323 def readMessageEnd(self):
Bryan Duxbury59d4efd2011-03-21 17:38:22 +0000324 assert self.state == CLEAR
David Reissabafd792010-09-27 17:28:15 +0000325 assert len(self.__structs) == 0
David Reissabafd792010-09-27 17:28:15 +0000326
327 def readStructBegin(self):
328 assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state
329 self.__structs.append((self.state, self.__last_fid))
330 self.state = FIELD_READ
331 self.__last_fid = 0
332
333 def readStructEnd(self):
334 assert self.state == FIELD_READ
335 self.state, self.__last_fid = self.__structs.pop()
336
337 def readCollectionBegin(self):
338 assert self.state in (VALUE_READ, CONTAINER_READ), self.state
339 size_type = self.__readUByte()
340 size = size_type >> 4
341 type = self.__getTType(size_type)
342 if size == 15:
343 size = self.__readSize()
344 self.__containers.append(self.state)
345 self.state = CONTAINER_READ
346 return type, size
347 readSetBegin = readCollectionBegin
348 readListBegin = readCollectionBegin
349
350 def readMapBegin(self):
351 assert self.state in (VALUE_READ, CONTAINER_READ), self.state
352 size = self.__readSize()
353 types = 0
354 if size > 0:
355 types = self.__readUByte()
356 vtype = self.__getTType(types)
357 ktype = self.__getTType(types >> 4)
358 self.__containers.append(self.state)
359 self.state = CONTAINER_READ
360 return (ktype, vtype, size)
361
362 def readCollectionEnd(self):
363 assert self.state == CONTAINER_READ, self.state
364 self.state = self.__containers.pop()
365 readSetEnd = readCollectionEnd
366 readListEnd = readCollectionEnd
367 readMapEnd = readCollectionEnd
368
369 def readBool(self):
370 if self.state == BOOL_READ:
Bryan Duxbury54df97c2011-07-13 18:11:29 +0000371 return self.__bool_value == CompactType.TRUE
David Reissabafd792010-09-27 17:28:15 +0000372 elif self.state == CONTAINER_READ:
Bryan Duxbury54df97c2011-07-13 18:11:29 +0000373 return self.__readByte() == CompactType.TRUE
David Reissabafd792010-09-27 17:28:15 +0000374 else:
Bryan Duxbury69720412012-01-03 17:32:30 +0000375 raise AssertionError("Invalid state in compact protocol: %d" %
376 self.state)
David Reissabafd792010-09-27 17:28:15 +0000377
378 readByte = reader(__readByte)
379 __readI16 = __readZigZag
380 readI16 = reader(__readZigZag)
381 readI32 = reader(__readZigZag)
382 readI64 = reader(__readZigZag)
383
384 @reader
385 def readDouble(self):
386 buff = self.trans.readAll(8)
Roger Meier8c691fa2013-11-05 04:54:33 +0100387 val, = unpack('<d', buff)
David Reissabafd792010-09-27 17:28:15 +0000388 return val
389
390 def __readString(self):
391 len = self.__readSize()
392 return self.trans.readAll(len)
393 readString = reader(__readString)
394
395 def __getTType(self, byte):
396 return TTYPES[byte & 0x0f]
397
398
399class TCompactProtocolFactory:
400 def __init__(self):
401 pass
402
403 def getProtocol(self, trans):
404 return TCompactProtocol(trans)