blob: f01c56f65dd26aa1f0b23535a0cea166032bfb0b [file] [log] [blame]
WangYaofuc1a78ba2016-01-28 19:29:54 +08001--
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
20require 'TProtocol'
Thomaseb684d32024-07-28 15:32:23 +020021local libluabpack = require 'libluabpack'
22local libluabitwise = require 'libluabitwise'
23local liblualongnumber = require 'liblualongnumber'
WangYaofuc1a78ba2016-01-28 19:29:54 +080024
25TCompactProtocol = __TObject.new(TProtocolBase, {
26 __type = 'TCompactProtocol',
27 COMPACT_PROTOCOL_ID = 0x82,
28 COMPACT_VERSION = 1,
29 COMPACT_VERSION_MASK = 0x1f,
30 COMPACT_TYPE_MASK = 0xE0,
31 COMPACT_TYPE_BITS = 0x07,
32 COMPACT_TYPE_SHIFT_AMOUNT = 5,
33
34 -- Used to keep track of the last field for the current and previous structs,
35 -- so we can do the delta stuff.
36 lastField = {},
37 lastFieldId = 0,
38 lastFieldIndex = 1,
39
40 -- If we encounter a boolean field begin, save the TField here so it can
41 -- have the value incorporated.
42 booleanFieldName = "",
43 booleanFieldId = 0,
44 booleanFieldPending = false,
45
46 -- If we read a field header, and it's a boolean field, save the boolean
47 -- value here so that readBool can use it.
48 boolValue = false,
49 boolValueIsNotNull = false,
50})
51
52TCompactType = {
53 COMPACT_BOOLEAN_TRUE = 0x01,
54 COMPACT_BOOLEAN_FALSE = 0x02,
55 COMPACT_BYTE = 0x03,
56 COMPACT_I16 = 0x04,
57 COMPACT_I32 = 0x05,
58 COMPACT_I64 = 0x06,
59 COMPACT_DOUBLE = 0x07,
60 COMPACT_BINARY = 0x08,
61 COMPACT_LIST = 0x09,
62 COMPACT_SET = 0x0A,
63 COMPACT_MAP = 0x0B,
Thomaseb684d32024-07-28 15:32:23 +020064 COMPACT_STRUCT = 0x0C,
65 COMPACT_UUID = 0x0D,
WangYaofuc1a78ba2016-01-28 19:29:54 +080066}
67
68TTypeToCompactType = {}
69TTypeToCompactType[TType.STOP] = TType.STOP
70TTypeToCompactType[TType.BOOL] = TCompactType.COMPACT_BOOLEAN_TRUE
71TTypeToCompactType[TType.BYTE] = TCompactType.COMPACT_BYTE
72TTypeToCompactType[TType.I16] = TCompactType.COMPACT_I16
73TTypeToCompactType[TType.I32] = TCompactType.COMPACT_I32
74TTypeToCompactType[TType.I64] = TCompactType.COMPACT_I64
75TTypeToCompactType[TType.DOUBLE] = TCompactType.COMPACT_DOUBLE
76TTypeToCompactType[TType.STRING] = TCompactType.COMPACT_BINARY
77TTypeToCompactType[TType.LIST] = TCompactType.COMPACT_LIST
78TTypeToCompactType[TType.SET] = TCompactType.COMPACT_SET
79TTypeToCompactType[TType.MAP] = TCompactType.COMPACT_MAP
80TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT
Thomaseb684d32024-07-28 15:32:23 +020081TTypeToCompactType[TType.UUID] = TCompactType.COMPACT_UUID
WangYaofuc1a78ba2016-01-28 19:29:54 +080082
83CompactTypeToTType = {}
Thomaseb684d32024-07-28 15:32:23 +020084CompactTypeToTType[TType.STOP] = TType.STOP
85CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL
WangYaofuc1a78ba2016-01-28 19:29:54 +080086CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL
Thomaseb684d32024-07-28 15:32:23 +020087CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE
88CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16
89CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32
90CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64
91CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE
92CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING
93CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST
94CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET
95CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP
96CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT
97CompactTypeToTType[TCompactType.COMPACT_UUID] = TType.UUID
WangYaofuc1a78ba2016-01-28 19:29:54 +080098
99function TCompactProtocol:resetLastField()
100 self.lastField = {}
101 self.lastFieldId = 0
102 self.lastFieldIndex = 1
103end
104
105function TCompactProtocol:packCompactType(ktype, vtype)
106 return libluabitwise.bor(libluabitwise.shiftl(ktype, 4), vtype)
107end
108
109function TCompactProtocol:writeMessageBegin(name, ttype, seqid)
110 self:writeByte(TCompactProtocol.COMPACT_PROTOCOL_ID)
111 self:writeByte(libluabpack.packMesgType(TCompactProtocol.COMPACT_VERSION,
112 TCompactProtocol.COMPACT_VERSION_MASK,ttype,
113 TCompactProtocol.COMPACT_TYPE_SHIFT_AMOUNT,
114 TCompactProtocol.COMPACT_TYPE_MASK))
115 self:writeVarint32(seqid)
116 self:writeString(name)
117 self:resetLastField()
118end
119
120function TCompactProtocol:writeMessageEnd()
121end
122
123function TCompactProtocol:writeStructBegin(name)
WangYaofuc1a78ba2016-01-28 19:29:54 +0800124 self.lastField[self.lastFieldIndex] = self.lastFieldId
longzhiri21b3e462020-08-08 15:24:10 +0800125 self.lastFieldIndex = self.lastFieldIndex + 1
WangYaofuc1a78ba2016-01-28 19:29:54 +0800126 self.lastFieldId = 0
127end
128
129function TCompactProtocol:writeStructEnd()
xiongjieqinga5b2bf52019-09-26 18:27:25 +0800130 self.lastFieldIndex = self.lastFieldIndex - 1
Jeffrey Han13662dd2020-12-17 13:12:10 -0800131 self.lastFieldId = self.lastField[self.lastFieldIndex]
WangYaofuc1a78ba2016-01-28 19:29:54 +0800132end
133
134function TCompactProtocol:writeFieldBegin(name, ttype, id)
135 if ttype == TType.BOOL then
136 self.booleanFieldName = name
137 self.booleanFieldId = id
138 self.booleanFieldPending = true
139 else
140 self:writeFieldBeginInternal(name, ttype, id, -1)
141 end
142end
143
144function TCompactProtocol:writeFieldEnd()
145end
146
147function TCompactProtocol:writeFieldStop()
148 self:writeByte(TType.STOP);
149end
150
151function TCompactProtocol:writeMapBegin(ktype, vtype, size)
152 if size == 0 then
153 self:writeByte(0)
154 else
155 self:writeVarint32(size)
156 self:writeByte(self:packCompactType(TTypeToCompactType[ktype], TTypeToCompactType[vtype]))
157 end
158end
159
160function TCompactProtocol:writeMapEnd()
161end
162
163function TCompactProtocol:writeListBegin(etype, size)
164 self:writeCollectionBegin(etype, size)
165end
166
167function TCompactProtocol:writeListEnd()
168end
169
170function TCompactProtocol:writeSetBegin(etype, size)
171 self:writeCollectionBegin(etype, size)
172end
173
174function TCompactProtocol:writeSetEnd()
175end
176
177function TCompactProtocol:writeBool(bool)
178 local value = TCompactType.COMPACT_BOOLEAN_FALSE
179 if bool then
180 value = TCompactType.COMPACT_BOOLEAN_TRUE
181 end
WangYaofuc1a78ba2016-01-28 19:29:54 +0800182 if self.booleanFieldPending then
183 self:writeFieldBeginInternal(self.booleanFieldName, TType.BOOL, self.booleanFieldId, value)
184 self.booleanFieldPending = false
185 else
186 self:writeByte(value)
187 end
188end
189
190function TCompactProtocol:writeByte(byte)
191 local buff = libluabpack.bpack('c', byte)
192 self.trans:write(buff)
193end
194
195function TCompactProtocol:writeI16(i16)
196 self:writeVarint32(libluabpack.i32ToZigzag(i16))
197end
198
199function TCompactProtocol:writeI32(i32)
200 self:writeVarint32(libluabpack.i32ToZigzag(i32))
201end
202
Thomaseb684d32024-07-28 15:32:23 +0200203function TCompactProtocol:writeUI32(i32)
204 local buff = libluabpack.bpack('I', i32)
205 self.trans:write(buff)
206end
207
WangYaofuc1a78ba2016-01-28 19:29:54 +0800208function TCompactProtocol:writeI64(i64)
209 self:writeVarint64(libluabpack.i64ToZigzag(i64))
210end
211
212function TCompactProtocol:writeDouble(dub)
213 local buff = libluabpack.bpack('d', dub)
214 self.trans:write(buff)
215end
216
217function TCompactProtocol:writeString(str)
218 -- Should be utf-8
219 self:writeBinary(str)
220end
221
Thomaseb684d32024-07-28 15:32:23 +0200222function TCompactProtocol:writeUuid(uuid)
223 self:writeUI32(uuid.two)
224 self:writeUI32(uuid.three)
225 self:writeUI32(uuid.zero)
226 self:writeUI32(uuid.one)
227end
228
WangYaofuc1a78ba2016-01-28 19:29:54 +0800229function TCompactProtocol:writeBinary(str)
230 -- Should be utf-8
231 self:writeVarint32(string.len(str))
232 self.trans:write(str)
233end
234
235function TCompactProtocol:writeFieldBeginInternal(name, ttype, id, typeOverride)
236 if typeOverride == -1 then
237 typeOverride = TTypeToCompactType[ttype]
238 end
239 local offset = id - self.lastFieldId
240 if id > self.lastFieldId and offset <= 15 then
241 self:writeByte(libluabitwise.bor(libluabitwise.shiftl(offset, 4), typeOverride))
242 else
243 self:writeByte(typeOverride)
244 self:writeI16(id)
245 end
246 self.lastFieldId = id
247end
248
249function TCompactProtocol:writeCollectionBegin(etype, size)
250 if size <= 14 then
251 self:writeByte(libluabitwise.bor(libluabitwise.shiftl(size, 4), TTypeToCompactType[etype]))
252 else
253 self:writeByte(libluabitwise.bor(0xf0, TTypeToCompactType[etype]))
254 self:writeVarint32(size)
255 end
256end
257
258function TCompactProtocol:writeVarint32(i32)
259 -- Should be utf-8
260 local str = libluabpack.toVarint32(i32)
261 self.trans:write(str)
262end
263
264function TCompactProtocol:writeVarint64(i64)
265 -- Should be utf-8
266 local str = libluabpack.toVarint64(i64)
267 self.trans:write(str)
268end
269
270function TCompactProtocol:readMessageBegin()
271 local protocolId = self:readSignByte()
272 if protocolId ~= self.COMPACT_PROTOCOL_ID then
273 terror(TProtocolException:new{
274 message = "Expected protocol id " .. self.COMPACT_PROTOCOL_ID .. " but got " .. protocolId})
275 end
276 local versionAndType = self:readSignByte()
277 local version = libluabitwise.band(versionAndType, self.COMPACT_VERSION_MASK)
278 local ttype = libluabitwise.band(libluabitwise.shiftr(versionAndType,
279 self.COMPACT_TYPE_SHIFT_AMOUNT), self.COMPACT_TYPE_BITS)
280 if version ~= self.COMPACT_VERSION then
281 terror(TProtocolException:new{
282 message = "Expected version " .. self.COMPACT_VERSION .. " but got " .. version})
283 end
284 local seqid = self:readVarint32()
285 local name = self:readString()
286 return name, ttype, seqid
287end
288
289function TCompactProtocol:readMessageEnd()
290end
291
292function TCompactProtocol:readStructBegin()
293 self.lastField[self.lastFieldIndex] = self.lastFieldId
294 self.lastFieldIndex = self.lastFieldIndex + 1
295 self.lastFieldId = 0
296 return nil
297end
298
299function TCompactProtocol:readStructEnd()
300 self.lastFieldIndex = self.lastFieldIndex - 1
301 self.lastFieldId = self.lastField[self.lastFieldIndex]
302end
303
304function TCompactProtocol:readFieldBegin()
305 local field_and_ttype = self:readSignByte()
306 local ttype = self:getTType(field_and_ttype)
307 if ttype == TType.STOP then
308 return nil, ttype, 0
309 end
Jeffrey Han5751ddf2020-10-01 16:17:17 -0700310 local modifier = libluabitwise.shiftr(field_and_ttype, 4)
WangYaofuc1a78ba2016-01-28 19:29:54 +0800311 local id = 0
312 if modifier == 0 then
313 id = self:readI16()
314 else
315 id = self.lastFieldId + modifier
316 end
Jeffrey Han5751ddf2020-10-01 16:17:17 -0700317 local type = libluabitwise.band(field_and_ttype, 0x0f)
318 if type == TCompactType.COMPACT_BOOLEAN_TRUE then
319 self.boolValue = true
320 self.boolValueIsNotNull = true
321 elseif type == TCompactType.COMPACT_BOOLEAN_FALSE then
322 self.boolValue = false
323 self.boolValueIsNotNull = true
WangYaofuc1a78ba2016-01-28 19:29:54 +0800324 end
325 self.lastFieldId = id
326 return nil, ttype, id
327end
328
329function TCompactProtocol:readFieldEnd()
330end
331
332function TCompactProtocol:readMapBegin()
333 local size = self:readVarint32()
Jeffrey Han7b712f42020-02-20 14:18:23 -0800334 local kvtype = 0
335 if size > 0 then
336 kvtype = self:readSignByte()
WangYaofuc1a78ba2016-01-28 19:29:54 +0800337 end
WangYaofuc1a78ba2016-01-28 19:29:54 +0800338 local ktype = self:getTType(libluabitwise.shiftr(kvtype, 4))
339 local vtype = self:getTType(kvtype)
340 return ktype, vtype, size
341end
342
343function TCompactProtocol:readMapEnd()
344end
345
346function TCompactProtocol:readListBegin()
347 local size_and_type = self:readSignByte()
348 local size = libluabitwise.band(libluabitwise.shiftr(size_and_type, 4), 0x0f)
349 if size == 15 then
350 size = self:readVarint32()
351 end
352 if size < 0 then
353 return nil,nil
354 end
355 local etype = self:getTType(libluabitwise.band(size_and_type, 0x0f))
356 return etype, size
357end
358
359function TCompactProtocol:readListEnd()
360end
361
362function TCompactProtocol:readSetBegin()
363 return self:readListBegin()
364end
365
366function TCompactProtocol:readSetEnd()
367end
368
369function TCompactProtocol:readBool()
Jeffrey Han5751ddf2020-10-01 16:17:17 -0700370 if self.boolValueIsNotNull then
371 self.boolValueIsNotNull = false
372 return self.boolValue
WangYaofuc1a78ba2016-01-28 19:29:54 +0800373 end
374 local val = self:readSignByte()
375 if val == TCompactType.COMPACT_BOOLEAN_TRUE then
376 return true
377 end
378 return false
379end
380
381function TCompactProtocol:readByte()
382 local buff = self.trans:readAll(1)
383 local val = libluabpack.bunpack('c', buff)
384 return val
385end
386
387function TCompactProtocol:readSignByte()
388 local buff = self.trans:readAll(1)
389 local val = libluabpack.bunpack('C', buff)
390 return val
391end
392
393function TCompactProtocol:readI16()
394 return self:readI32()
395end
396
397function TCompactProtocol:readI32()
398 local v = self:readVarint32()
399 local value = libluabpack.zigzagToI32(v)
400 return value
401end
402
Thomaseb684d32024-07-28 15:32:23 +0200403function TCompactProtocol:readUI32()
404 local buff = self.trans:readAll(4)
405 local val = libluabpack.bunpack('I', buff)
406 return val
407end
408
WangYaofuc1a78ba2016-01-28 19:29:54 +0800409function TCompactProtocol:readI64()
410 local value = self:readVarint64()
411 return value
412end
413
414function TCompactProtocol:readDouble()
415 local buff = self.trans:readAll(8)
416 local val = libluabpack.bunpack('d', buff)
417 return val
418end
419
420function TCompactProtocol:readString()
421 return self:readBinary()
422end
423
Thomaseb684d32024-07-28 15:32:23 +0200424function TCompactProtocol:readUuid()
425 local a = self:readUI32()
426 local b = self:readUI32()
427 local c = self:readUI32()
428 local d = self:readUI32()
429 return TUUID:new {
430 zero = c,
431 one = d,
432 two = a,
433 three = b
434 }
435end
436
WangYaofuc1a78ba2016-01-28 19:29:54 +0800437function TCompactProtocol:readBinary()
438 local size = self:readVarint32()
439 if size <= 0 then
440 return ""
441 end
442 return self.trans:readAll(size)
443end
444
445function TCompactProtocol:readVarint32()
446 local shiftl = 0
447 local result = 0
448 while true do
449 b = self:readByte()
450 result = libluabitwise.bor(result,
451 libluabitwise.shiftl(libluabitwise.band(b, 0x7f), shiftl))
452 if libluabitwise.band(b, 0x80) ~= 0x80 then
453 break
454 end
455 shiftl = shiftl + 7
456 end
457 return result
458end
459
460function TCompactProtocol:readVarint64()
461 local result = liblualongnumber.new
462 local data = result(0)
463 local shiftl = 0
464 while true do
Jeffrey Han7b712f42020-02-20 14:18:23 -0800465 b = self:readSignByte()
WangYaofuc1a78ba2016-01-28 19:29:54 +0800466 endFlag, data = libluabpack.fromVarint64(b, shiftl, data)
467 shiftl = shiftl + 7
468 if endFlag == 0 then
469 break
470 end
471 end
472 return data
473end
474
475function TCompactProtocol:getTType(ctype)
476 return CompactTypeToTType[libluabitwise.band(ctype, 0x0f)]
477end
478
479TCompactProtocolFactory = TProtocolFactory:new{
480 __type = 'TCompactProtocolFactory',
481}
482
483function TCompactProtocolFactory:getProtocol(trans)
484 -- TODO Enforce that this must be a transport class (ie not a bool)
485 if not trans then
486 terror(TProtocolException:new{
487 message = 'Must supply a transport to ' .. ttype(self)
488 })
489 end
490 return TCompactProtocol:new{
491 trans = trans
492 }
493end