tiny_thrift 1.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/server.rb +82 -0
  7. data/benchmark/thin_server.rb +44 -0
  8. data/ext/binary_protocol_accelerated.c +460 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/bytes.c +36 -0
  11. data/ext/bytes.h +31 -0
  12. data/ext/compact_protocol.c +635 -0
  13. data/ext/compact_protocol.h +20 -0
  14. data/ext/constants.h +96 -0
  15. data/ext/extconf.rb +32 -0
  16. data/ext/macros.h +41 -0
  17. data/ext/memory_buffer.c +134 -0
  18. data/ext/memory_buffer.h +20 -0
  19. data/ext/protocol.c +0 -0
  20. data/ext/protocol.h +0 -0
  21. data/ext/strlcpy.c +41 -0
  22. data/ext/strlcpy.h +34 -0
  23. data/ext/struct.c +688 -0
  24. data/ext/struct.h +25 -0
  25. data/ext/thrift_native.c +195 -0
  26. data/lib/thrift.rb +66 -0
  27. data/lib/thrift/bytes.rb +131 -0
  28. data/lib/thrift/client.rb +62 -0
  29. data/lib/thrift/core_ext.rb +23 -0
  30. data/lib/thrift/core_ext/fixnum.rb +29 -0
  31. data/lib/thrift/exceptions.rb +87 -0
  32. data/lib/thrift/processor.rb +57 -0
  33. data/lib/thrift/protocol/base_protocol.rb +377 -0
  34. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  35. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  36. data/lib/thrift/protocol/compact_protocol.rb +434 -0
  37. data/lib/thrift/protocol/json_protocol.rb +769 -0
  38. data/lib/thrift/serializer/deserializer.rb +33 -0
  39. data/lib/thrift/serializer/serializer.rb +34 -0
  40. data/lib/thrift/server/base_server.rb +31 -0
  41. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  42. data/lib/thrift/server/nonblocking_server.rb +305 -0
  43. data/lib/thrift/server/simple_server.rb +43 -0
  44. data/lib/thrift/server/thin_http_server.rb +91 -0
  45. data/lib/thrift/server/thread_pool_server.rb +75 -0
  46. data/lib/thrift/server/threaded_server.rb +47 -0
  47. data/lib/thrift/struct.rb +237 -0
  48. data/lib/thrift/struct_union.rb +192 -0
  49. data/lib/thrift/thrift_native.rb +24 -0
  50. data/lib/thrift/transport/base_server_transport.rb +37 -0
  51. data/lib/thrift/transport/base_transport.rb +109 -0
  52. data/lib/thrift/transport/buffered_transport.rb +114 -0
  53. data/lib/thrift/transport/framed_transport.rb +117 -0
  54. data/lib/thrift/transport/http_client_transport.rb +56 -0
  55. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  56. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  57. data/lib/thrift/transport/server_socket.rb +63 -0
  58. data/lib/thrift/transport/socket.rb +139 -0
  59. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  60. data/lib/thrift/transport/unix_socket.rb +40 -0
  61. data/lib/thrift/types.rb +101 -0
  62. data/lib/thrift/union.rb +179 -0
  63. data/lib/tiny_thrift.rb +1 -0
  64. data/spec/ThriftSpec.thrift +183 -0
  65. data/spec/base_protocol_spec.rb +217 -0
  66. data/spec/base_transport_spec.rb +350 -0
  67. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  68. data/spec/binary_protocol_spec.rb +66 -0
  69. data/spec/binary_protocol_spec_shared.rb +455 -0
  70. data/spec/bytes_spec.rb +160 -0
  71. data/spec/client_spec.rb +99 -0
  72. data/spec/compact_protocol_spec.rb +143 -0
  73. data/spec/exception_spec.rb +141 -0
  74. data/spec/http_client_spec.rb +120 -0
  75. data/spec/json_protocol_spec.rb +513 -0
  76. data/spec/nonblocking_server_spec.rb +263 -0
  77. data/spec/processor_spec.rb +80 -0
  78. data/spec/serializer_spec.rb +67 -0
  79. data/spec/server_socket_spec.rb +79 -0
  80. data/spec/server_spec.rb +147 -0
  81. data/spec/socket_spec.rb +61 -0
  82. data/spec/socket_spec_shared.rb +104 -0
  83. data/spec/spec_helper.rb +61 -0
  84. data/spec/struct_nested_containers_spec.rb +191 -0
  85. data/spec/struct_spec.rb +293 -0
  86. data/spec/thin_http_server_spec.rb +141 -0
  87. data/spec/types_spec.rb +115 -0
  88. data/spec/union_spec.rb +203 -0
  89. data/spec/unix_socket_spec.rb +107 -0
  90. metadata +313 -0
@@ -0,0 +1,237 @@
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
+ module Thrift
21
+ class BinaryProtocol < BaseProtocol
22
+ VERSION_MASK = 0xffff0000
23
+ VERSION_1 = 0x80010000
24
+ TYPE_MASK = 0x000000ff
25
+
26
+ attr_reader :strict_read, :strict_write
27
+
28
+ def initialize(trans, strict_read=true, strict_write=true)
29
+ super(trans)
30
+ @strict_read = strict_read
31
+ @strict_write = strict_write
32
+
33
+ # Pre-allocated read buffer for fixed-size read methods. Needs to be at least 8 bytes long for
34
+ # read_i64() and read_double().
35
+ @rbuf = Bytes.empty_byte_buffer(8)
36
+ end
37
+
38
+ def write_message_begin(name, type, seqid)
39
+ # this is necessary because we added (needed) bounds checking to
40
+ # write_i32, and 0x80010000 is too big for that.
41
+ if strict_write
42
+ write_i16(VERSION_1 >> 16)
43
+ write_i16(type)
44
+ write_string(name)
45
+ write_i32(seqid)
46
+ else
47
+ write_string(name)
48
+ write_byte(type)
49
+ write_i32(seqid)
50
+ end
51
+ end
52
+
53
+ def write_struct_begin(name); nil; end
54
+
55
+ def write_field_begin(name, type, id)
56
+ write_byte(type)
57
+ write_i16(id)
58
+ end
59
+
60
+ def write_field_stop
61
+ write_byte(Thrift::Types::STOP)
62
+ end
63
+
64
+ def write_map_begin(ktype, vtype, size)
65
+ write_byte(ktype)
66
+ write_byte(vtype)
67
+ write_i32(size)
68
+ end
69
+
70
+ def write_list_begin(etype, size)
71
+ write_byte(etype)
72
+ write_i32(size)
73
+ end
74
+
75
+ def write_set_begin(etype, size)
76
+ write_byte(etype)
77
+ write_i32(size)
78
+ end
79
+
80
+ def write_bool(bool)
81
+ write_byte(bool ? 1 : 0)
82
+ end
83
+
84
+ def write_byte(byte)
85
+ raise RangeError if byte < -2**31 || byte >= 2**32
86
+ trans.write([byte].pack('c'))
87
+ end
88
+
89
+ def write_i16(i16)
90
+ trans.write([i16].pack('n'))
91
+ end
92
+
93
+ def write_i32(i32)
94
+ raise RangeError if i32 < -2**31 || i32 >= 2**31
95
+ trans.write([i32].pack('N'))
96
+ end
97
+
98
+ def write_i64(i64)
99
+ raise RangeError if i64 < -2**63 || i64 >= 2**64
100
+ hi = i64 >> 32
101
+ lo = i64 & 0xffffffff
102
+ trans.write([hi, lo].pack('N2'))
103
+ end
104
+
105
+ def write_double(dub)
106
+ trans.write([dub].pack('G'))
107
+ end
108
+
109
+ def write_string(str)
110
+ buf = Bytes.convert_to_utf8_byte_buffer(str)
111
+ write_binary(buf)
112
+ end
113
+
114
+ def write_binary(buf)
115
+ write_i32(buf.bytesize)
116
+ trans.write(buf)
117
+ end
118
+
119
+ def read_message_begin
120
+ version = read_i32
121
+ if version < 0
122
+ if (version & VERSION_MASK != VERSION_1)
123
+ raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Missing version identifier')
124
+ end
125
+ type = version & TYPE_MASK
126
+ name = read_string
127
+ seqid = read_i32
128
+ [name, type, seqid]
129
+ else
130
+ if strict_read
131
+ raise ProtocolException.new(ProtocolException::BAD_VERSION, 'No version identifier, old protocol client?')
132
+ end
133
+ name = trans.read_all(version)
134
+ type = read_byte
135
+ seqid = read_i32
136
+ [name, type, seqid]
137
+ end
138
+ end
139
+
140
+ def read_struct_begin; nil; end
141
+
142
+ def read_field_begin
143
+ type = read_byte
144
+ if (type == Types::STOP)
145
+ [nil, type, 0]
146
+ else
147
+ id = read_i16
148
+ [nil, type, id]
149
+ end
150
+ end
151
+
152
+ def read_map_begin
153
+ ktype = read_byte
154
+ vtype = read_byte
155
+ size = read_i32
156
+ [ktype, vtype, size]
157
+ end
158
+
159
+ def read_list_begin
160
+ etype = read_byte
161
+ size = read_i32
162
+ [etype, size]
163
+ end
164
+
165
+ def read_set_begin
166
+ etype = read_byte
167
+ size = read_i32
168
+ [etype, size]
169
+ end
170
+
171
+ def read_bool
172
+ byte = read_byte
173
+ byte != 0
174
+ end
175
+
176
+ def read_byte
177
+ val = trans.read_byte
178
+ if (val > 0x7f)
179
+ val = 0 - ((val - 1) ^ 0xff)
180
+ end
181
+ val
182
+ end
183
+
184
+ def read_i16
185
+ trans.read_into_buffer(@rbuf, 2)
186
+ val, = @rbuf.unpack('n')
187
+ if (val > 0x7fff)
188
+ val = 0 - ((val - 1) ^ 0xffff)
189
+ end
190
+ val
191
+ end
192
+
193
+ def read_i32
194
+ trans.read_into_buffer(@rbuf, 4)
195
+ val, = @rbuf.unpack('N')
196
+ if (val > 0x7fffffff)
197
+ val = 0 - ((val - 1) ^ 0xffffffff)
198
+ end
199
+ val
200
+ end
201
+
202
+ def read_i64
203
+ trans.read_into_buffer(@rbuf, 8)
204
+ hi, lo = @rbuf.unpack('N2')
205
+ if (hi > 0x7fffffff)
206
+ hi ^= 0xffffffff
207
+ lo ^= 0xffffffff
208
+ 0 - (hi << 32) - lo - 1
209
+ else
210
+ (hi << 32) + lo
211
+ end
212
+ end
213
+
214
+ def read_double
215
+ trans.read_into_buffer(@rbuf, 8)
216
+ val = @rbuf.unpack('G').first
217
+ val
218
+ end
219
+
220
+ def read_string
221
+ buffer = read_binary
222
+ Bytes.convert_to_string(buffer)
223
+ end
224
+
225
+ def read_binary
226
+ size = read_i32
227
+ trans.read_all(size)
228
+ end
229
+
230
+ end
231
+
232
+ class BinaryProtocolFactory < BaseProtocolFactory
233
+ def get_protocol(trans)
234
+ return Thrift::BinaryProtocol.new(trans)
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,39 @@
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
+ =begin
21
+ The only change required for a transport to support BinaryProtocolAccelerated is to implement 2 methods:
22
+ * borrow(size), which takes an optional argument and returns atleast _size_ bytes from the transport,
23
+ or the default buffer size if no argument is given
24
+ * consume!(size), which removes size bytes from the front of the buffer
25
+
26
+ See MemoryBuffer and BufferedTransport for examples.
27
+ =end
28
+
29
+ module Thrift
30
+ class BinaryProtocolAcceleratedFactory < BaseProtocolFactory
31
+ def get_protocol(trans)
32
+ if (defined? BinaryProtocolAccelerated)
33
+ BinaryProtocolAccelerated.new(trans)
34
+ else
35
+ BinaryProtocol.new(trans)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,434 @@
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
+ module Thrift
21
+ class CompactProtocol < BaseProtocol
22
+
23
+ PROTOCOL_ID = [0x82].pack('c').unpack('c').first
24
+ VERSION = 1
25
+ VERSION_MASK = 0x1f
26
+ TYPE_MASK = 0xE0
27
+ TYPE_SHIFT_AMOUNT = 5
28
+
29
+ TSTOP = ["", Types::STOP, 0]
30
+
31
+ #
32
+ # All of the on-wire type codes.
33
+ #
34
+ class CompactTypes
35
+ BOOLEAN_TRUE = 0x01
36
+ BOOLEAN_FALSE = 0x02
37
+ BYTE = 0x03
38
+ I16 = 0x04
39
+ I32 = 0x05
40
+ I64 = 0x06
41
+ DOUBLE = 0x07
42
+ BINARY = 0x08
43
+ LIST = 0x09
44
+ SET = 0x0A
45
+ MAP = 0x0B
46
+ STRUCT = 0x0C
47
+
48
+ def self.is_bool_type?(b)
49
+ (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE
50
+ end
51
+
52
+ COMPACT_TO_TTYPE = {
53
+ Types::STOP => Types::STOP,
54
+ BOOLEAN_FALSE => Types::BOOL,
55
+ BOOLEAN_TRUE => Types::BOOL,
56
+ BYTE => Types::BYTE,
57
+ I16 => Types::I16,
58
+ I32 => Types::I32,
59
+ I64 => Types::I64,
60
+ DOUBLE => Types::DOUBLE,
61
+ BINARY => Types::STRING,
62
+ LIST => Types::LIST,
63
+ SET => Types::SET,
64
+ MAP => Types::MAP,
65
+ STRUCT => Types::STRUCT
66
+ }
67
+
68
+ TTYPE_TO_COMPACT = {
69
+ Types::STOP => Types::STOP,
70
+ Types::BOOL => BOOLEAN_TRUE,
71
+ Types::BYTE => BYTE,
72
+ Types::I16 => I16,
73
+ Types::I32 => I32,
74
+ Types::I64 => I64,
75
+ Types::DOUBLE => DOUBLE,
76
+ Types::STRING => BINARY,
77
+ Types::LIST => LIST,
78
+ Types::SET => SET,
79
+ Types::MAP => MAP,
80
+ Types::STRUCT => STRUCT
81
+ }
82
+
83
+ def self.get_ttype(compact_type)
84
+ val = COMPACT_TO_TTYPE[compact_type & 0x0f]
85
+ raise "don't know what type: #{compact_type & 0x0f}" unless val
86
+ val
87
+ end
88
+
89
+ def self.get_compact_type(ttype)
90
+ val = TTYPE_TO_COMPACT[ttype]
91
+ raise "don't know what type: #{ttype & 0x0f}" unless val
92
+ val
93
+ end
94
+ end
95
+
96
+ def initialize(transport)
97
+ super(transport)
98
+
99
+ @last_field = [0]
100
+ @boolean_value = nil
101
+
102
+ # Pre-allocated read buffer for read_double().
103
+ @rbuf = Bytes.empty_byte_buffer(8)
104
+ end
105
+
106
+ def write_message_begin(name, type, seqid)
107
+ write_byte(PROTOCOL_ID)
108
+ write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK))
109
+ write_varint32(seqid)
110
+ write_string(name)
111
+ nil
112
+ end
113
+
114
+ def write_struct_begin(name)
115
+ @last_field.push(0)
116
+ nil
117
+ end
118
+
119
+ def write_struct_end
120
+ @last_field.pop
121
+ nil
122
+ end
123
+
124
+ def write_field_begin(name, type, id)
125
+ if type == Types::BOOL
126
+ # we want to possibly include the value, so we'll wait.
127
+ @boolean_field = [type, id]
128
+ else
129
+ write_field_begin_internal(type, id)
130
+ end
131
+ nil
132
+ end
133
+
134
+ #
135
+ # The workhorse of writeFieldBegin. It has the option of doing a
136
+ # 'type override' of the type header. This is used specifically in the
137
+ # boolean field case.
138
+ #
139
+ def write_field_begin_internal(type, id, type_override=nil)
140
+ last_id = @last_field.pop
141
+
142
+ # if there's a type override, use that.
143
+ typeToWrite = type_override || CompactTypes.get_compact_type(type)
144
+
145
+ # check if we can use delta encoding for the field id
146
+ if id > last_id && id - last_id <= 15
147
+ # write them together
148
+ write_byte((id - last_id) << 4 | typeToWrite)
149
+ else
150
+ # write them separate
151
+ write_byte(typeToWrite)
152
+ write_i16(id)
153
+ end
154
+
155
+ @last_field.push(id)
156
+ nil
157
+ end
158
+
159
+ def write_field_stop
160
+ write_byte(Types::STOP)
161
+ end
162
+
163
+ def write_map_begin(ktype, vtype, size)
164
+ if (size == 0)
165
+ write_byte(0)
166
+ else
167
+ write_varint32(size)
168
+ write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype))
169
+ end
170
+ end
171
+
172
+ def write_list_begin(etype, size)
173
+ write_collection_begin(etype, size)
174
+ end
175
+
176
+ def write_set_begin(etype, size)
177
+ write_collection_begin(etype, size);
178
+ end
179
+
180
+ def write_bool(bool)
181
+ type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE
182
+ unless @boolean_field.nil?
183
+ # we haven't written the field header yet
184
+ write_field_begin_internal(@boolean_field.first, @boolean_field.last, type)
185
+ @boolean_field = nil
186
+ else
187
+ # we're not part of a field, so just write the value.
188
+ write_byte(type)
189
+ end
190
+ end
191
+
192
+ def write_byte(byte)
193
+ @trans.write([byte].pack('c'))
194
+ end
195
+
196
+ def write_i16(i16)
197
+ write_varint32(int_to_zig_zag(i16))
198
+ end
199
+
200
+ def write_i32(i32)
201
+ write_varint32(int_to_zig_zag(i32))
202
+ end
203
+
204
+ def write_i64(i64)
205
+ write_varint64(long_to_zig_zag(i64))
206
+ end
207
+
208
+ def write_double(dub)
209
+ @trans.write([dub].pack("G").reverse)
210
+ end
211
+
212
+ def write_string(str)
213
+ buf = Bytes.convert_to_utf8_byte_buffer(str)
214
+ write_binary(buf)
215
+ end
216
+
217
+ def write_binary(buf)
218
+ write_varint32(buf.bytesize)
219
+ @trans.write(buf)
220
+ end
221
+
222
+ def read_message_begin
223
+ protocol_id = read_byte()
224
+ if protocol_id != PROTOCOL_ID
225
+ raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}")
226
+ end
227
+
228
+ version_and_type = read_byte()
229
+ version = version_and_type & VERSION_MASK
230
+ if (version != VERSION)
231
+ raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
232
+ end
233
+
234
+ type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03
235
+ seqid = read_varint32()
236
+ messageName = read_string()
237
+ [messageName, type, seqid]
238
+ end
239
+
240
+ def read_struct_begin
241
+ @last_field.push(0)
242
+ ""
243
+ end
244
+
245
+ def read_struct_end
246
+ @last_field.pop()
247
+ nil
248
+ end
249
+
250
+ def read_field_begin
251
+ type = read_byte()
252
+
253
+ # if it's a stop, then we can return immediately, as the struct is over.
254
+ if (type & 0x0f) == Types::STOP
255
+ TSTOP
256
+ else
257
+ field_id = nil
258
+
259
+ # mask off the 4 MSB of the type header. it could contain a field id delta.
260
+ modifier = (type & 0xf0) >> 4
261
+ if modifier == 0
262
+ # not a delta. look ahead for the zigzag varint field id.
263
+ @last_field.pop
264
+ field_id = read_i16()
265
+ else
266
+ # has a delta. add the delta to the last read field id.
267
+ field_id = @last_field.pop + modifier
268
+ end
269
+
270
+ # if this happens to be a boolean field, the value is encoded in the type
271
+ if CompactTypes.is_bool_type?(type)
272
+ # save the boolean value in a special instance variable.
273
+ @bool_value = (type & 0x0f) == CompactTypes::BOOLEAN_TRUE
274
+ end
275
+
276
+ # push the new field onto the field stack so we can keep the deltas going.
277
+ @last_field.push(field_id)
278
+ ["", CompactTypes.get_ttype(type & 0x0f), field_id]
279
+ end
280
+ end
281
+
282
+ def read_map_begin
283
+ size = read_varint32()
284
+ key_and_value_type = size == 0 ? 0 : read_byte()
285
+ [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size]
286
+ end
287
+
288
+ def read_list_begin
289
+ size_and_type = read_byte()
290
+ size = (size_and_type >> 4) & 0x0f
291
+ if size == 15
292
+ size = read_varint32()
293
+ end
294
+ type = CompactTypes.get_ttype(size_and_type)
295
+ [type, size]
296
+ end
297
+
298
+ def read_set_begin
299
+ read_list_begin
300
+ end
301
+
302
+ def read_bool
303
+ unless @bool_value.nil?
304
+ bv = @bool_value
305
+ @bool_value = nil
306
+ bv
307
+ else
308
+ read_byte() == CompactTypes::BOOLEAN_TRUE
309
+ end
310
+ end
311
+
312
+ def read_byte
313
+ val = trans.read_byte
314
+ if (val > 0x7f)
315
+ val = 0 - ((val - 1) ^ 0xff)
316
+ end
317
+ val
318
+ end
319
+
320
+ def read_i16
321
+ zig_zag_to_int(read_varint32())
322
+ end
323
+
324
+ def read_i32
325
+ zig_zag_to_int(read_varint32())
326
+ end
327
+
328
+ def read_i64
329
+ zig_zag_to_long(read_varint64())
330
+ end
331
+
332
+ def read_double
333
+ trans.read_into_buffer(@rbuf, 8)
334
+ val = @rbuf.reverse.unpack('G').first
335
+ val
336
+ end
337
+
338
+ def read_string
339
+ buffer = read_binary
340
+ Bytes.convert_to_string(buffer)
341
+ end
342
+
343
+ def read_binary
344
+ size = read_varint32()
345
+ trans.read_all(size)
346
+ end
347
+
348
+ private
349
+
350
+ #
351
+ # Abstract method for writing the start of lists and sets. List and sets on
352
+ # the wire differ only by the type indicator.
353
+ #
354
+ def write_collection_begin(elem_type, size)
355
+ if size <= 14
356
+ write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
357
+ else
358
+ write_byte(0xf0 | CompactTypes.get_compact_type(elem_type))
359
+ write_varint32(size)
360
+ end
361
+ end
362
+
363
+ def write_varint32(n)
364
+ # int idx = 0;
365
+ while true
366
+ if (n & ~0x7F) == 0
367
+ # i32buf[idx++] = (byte)n;
368
+ write_byte(n)
369
+ break
370
+ # return;
371
+ else
372
+ # i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
373
+ write_byte((n & 0x7F) | 0x80)
374
+ n = n >> 7
375
+ end
376
+ end
377
+ # trans_.write(i32buf, 0, idx);
378
+ end
379
+
380
+ SEVEN_BIT_MASK = 0x7F
381
+ EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK
382
+
383
+ def write_varint64(n)
384
+ while true
385
+ if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long...
386
+ write_byte(n)
387
+ break
388
+ else
389
+ write_byte((n & SEVEN_BIT_MASK) | 0x80)
390
+ n >>= 7
391
+ end
392
+ end
393
+ end
394
+
395
+ def read_varint32()
396
+ read_varint64()
397
+ end
398
+
399
+ def read_varint64()
400
+ shift = 0
401
+ result = 0
402
+ while true
403
+ b = read_byte()
404
+ result |= (b & 0x7f) << shift
405
+ break if (b & 0x80) != 0x80
406
+ shift += 7
407
+ end
408
+ result
409
+ end
410
+
411
+ def int_to_zig_zag(n)
412
+ (n << 1) ^ (n >> 31)
413
+ end
414
+
415
+ def long_to_zig_zag(l)
416
+ # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}"
417
+ (l << 1) ^ (l >> 63)
418
+ end
419
+
420
+ def zig_zag_to_int(n)
421
+ (n >> 1) ^ -(n & 1)
422
+ end
423
+
424
+ def zig_zag_to_long(n)
425
+ (n >> 1) ^ -(n & 1)
426
+ end
427
+ end
428
+
429
+ class CompactProtocolFactory < BaseProtocolFactory
430
+ def get_protocol(trans)
431
+ CompactProtocol.new(trans)
432
+ end
433
+ end
434
+ end