tiny_thrift 1.0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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