sessionm-thrift 0.8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +1 -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 +441 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/compact_protocol.c +618 -0
  11. data/ext/compact_protocol.h +20 -0
  12. data/ext/constants.h +96 -0
  13. data/ext/extconf.rb +30 -0
  14. data/ext/macros.h +41 -0
  15. data/ext/memory_buffer.c +131 -0
  16. data/ext/memory_buffer.h +20 -0
  17. data/ext/protocol.c +185 -0
  18. data/ext/protocol.h +20 -0
  19. data/ext/strlcpy.c +41 -0
  20. data/ext/strlcpy.h +30 -0
  21. data/ext/struct.c +691 -0
  22. data/ext/struct.h +25 -0
  23. data/ext/thrift_native.c +196 -0
  24. data/lib/thrift.rb +64 -0
  25. data/lib/thrift/client.rb +62 -0
  26. data/lib/thrift/core_ext.rb +23 -0
  27. data/lib/thrift/core_ext/fixnum.rb +29 -0
  28. data/lib/thrift/exceptions.rb +84 -0
  29. data/lib/thrift/processor.rb +57 -0
  30. data/lib/thrift/protocol/base_protocol.rb +290 -0
  31. data/lib/thrift/protocol/binary_protocol.rb +229 -0
  32. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  33. data/lib/thrift/protocol/compact_protocol.rb +426 -0
  34. data/lib/thrift/serializer/deserializer.rb +33 -0
  35. data/lib/thrift/serializer/serializer.rb +34 -0
  36. data/lib/thrift/server/base_server.rb +31 -0
  37. data/lib/thrift/server/mongrel_http_server.rb +58 -0
  38. data/lib/thrift/server/nonblocking_server.rb +305 -0
  39. data/lib/thrift/server/simple_server.rb +43 -0
  40. data/lib/thrift/server/thread_pool_server.rb +75 -0
  41. data/lib/thrift/server/threaded_server.rb +47 -0
  42. data/lib/thrift/struct.rb +237 -0
  43. data/lib/thrift/struct_union.rb +192 -0
  44. data/lib/thrift/thrift_native.rb +24 -0
  45. data/lib/thrift/transport/base_server_transport.rb +37 -0
  46. data/lib/thrift/transport/base_transport.rb +107 -0
  47. data/lib/thrift/transport/buffered_transport.rb +108 -0
  48. data/lib/thrift/transport/framed_transport.rb +116 -0
  49. data/lib/thrift/transport/http_client_transport.rb +51 -0
  50. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  51. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  52. data/lib/thrift/transport/server_socket.rb +63 -0
  53. data/lib/thrift/transport/socket.rb +137 -0
  54. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  55. data/lib/thrift/transport/unix_socket.rb +40 -0
  56. data/lib/thrift/types.rb +101 -0
  57. data/lib/thrift/union.rb +179 -0
  58. data/spec/ThriftSpec.thrift +132 -0
  59. data/spec/base_protocol_spec.rb +160 -0
  60. data/spec/base_transport_spec.rb +351 -0
  61. data/spec/binary_protocol_accelerated_spec.rb +46 -0
  62. data/spec/binary_protocol_spec.rb +61 -0
  63. data/spec/binary_protocol_spec_shared.rb +375 -0
  64. data/spec/client_spec.rb +100 -0
  65. data/spec/compact_protocol_spec.rb +144 -0
  66. data/spec/exception_spec.rb +142 -0
  67. data/spec/http_client_spec.rb +64 -0
  68. data/spec/mongrel_http_server_spec.rb +117 -0
  69. data/spec/nonblocking_server_spec.rb +265 -0
  70. data/spec/processor_spec.rb +83 -0
  71. data/spec/serializer_spec.rb +69 -0
  72. data/spec/server_socket_spec.rb +80 -0
  73. data/spec/server_spec.rb +159 -0
  74. data/spec/socket_spec.rb +61 -0
  75. data/spec/socket_spec_shared.rb +104 -0
  76. data/spec/spec_helper.rb +58 -0
  77. data/spec/struct_spec.rb +295 -0
  78. data/spec/types_spec.rb +116 -0
  79. data/spec/union_spec.rb +193 -0
  80. data/spec/unix_socket_spec.rb +108 -0
  81. metadata +247 -0
data/ext/protocol.h ADDED
@@ -0,0 +1,20 @@
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
+ void Init_protocol();
data/ext/strlcpy.c ADDED
@@ -0,0 +1,41 @@
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 "strlcpy.h"
21
+
22
+ #ifndef HAVE_STRLCPY
23
+ #define HAVE_STRLCPY
24
+ size_t
25
+ strlcpy (char *dst, const char *src, size_t dst_sz)
26
+ {
27
+ size_t n;
28
+
29
+ for (n = 0; n < dst_sz; n++) {
30
+ if ((*dst++ = *src++) == '\0')
31
+ break;
32
+ }
33
+
34
+ if (n < dst_sz)
35
+ return n;
36
+ if (n > 0)
37
+ *(dst - 1) = '\0';
38
+ return n + strlen (src);
39
+ }
40
+ #endif
41
+
data/ext/strlcpy.h ADDED
@@ -0,0 +1,30 @@
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
+
21
+ #include <sys/types.h>
22
+ #include <string.h>
23
+
24
+ #ifndef HAVE_STRLCPY
25
+ size_t
26
+ strlcpy (char *dst, const char *src, size_t dst_sz);
27
+ #else
28
+ extern size_t strlcpy(char *, const char *, size_t);
29
+ #endif
30
+
data/ext/struct.c ADDED
@@ -0,0 +1,691 @@
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 "struct.h"
21
+ #include "constants.h"
22
+ #include "macros.h"
23
+ #include "strlcpy.h"
24
+
25
+ VALUE thrift_union_class;
26
+
27
+ ID setfield_id;
28
+ ID setvalue_id;
29
+
30
+ ID to_s_method_id;
31
+ ID name_to_id_method_id;
32
+ static ID sorted_field_ids_method_id;
33
+
34
+ #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
35
+ #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
36
+
37
+ //-------------------------------------------
38
+ // Writing section
39
+ //-------------------------------------------
40
+
41
+ // default fn pointers for protocol stuff here
42
+
43
+ VALUE default_write_bool(VALUE protocol, VALUE value) {
44
+ rb_funcall(protocol, write_boolean_method_id, 1, value);
45
+ return Qnil;
46
+ }
47
+
48
+ VALUE default_write_byte(VALUE protocol, VALUE value) {
49
+ rb_funcall(protocol, write_byte_method_id, 1, value);
50
+ return Qnil;
51
+ }
52
+
53
+ VALUE default_write_i16(VALUE protocol, VALUE value) {
54
+ rb_funcall(protocol, write_i16_method_id, 1, value);
55
+ return Qnil;
56
+ }
57
+
58
+ VALUE default_write_i32(VALUE protocol, VALUE value) {
59
+ rb_funcall(protocol, write_i32_method_id, 1, value);
60
+ return Qnil;
61
+ }
62
+
63
+ VALUE default_write_i64(VALUE protocol, VALUE value) {
64
+ rb_funcall(protocol, write_i64_method_id, 1, value);
65
+ return Qnil;
66
+ }
67
+
68
+ VALUE default_write_double(VALUE protocol, VALUE value) {
69
+ rb_funcall(protocol, write_double_method_id, 1, value);
70
+ return Qnil;
71
+ }
72
+
73
+ VALUE default_write_string(VALUE protocol, VALUE value) {
74
+ rb_funcall(protocol, write_string_method_id, 1, value);
75
+ return Qnil;
76
+ }
77
+
78
+ VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
79
+ rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
80
+ return Qnil;
81
+ }
82
+
83
+ VALUE default_write_list_end(VALUE protocol) {
84
+ rb_funcall(protocol, write_list_end_method_id, 0);
85
+ return Qnil;
86
+ }
87
+
88
+ VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
89
+ rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
90
+ return Qnil;
91
+ }
92
+
93
+ VALUE default_write_set_end(VALUE protocol) {
94
+ rb_funcall(protocol, write_set_end_method_id, 0);
95
+ return Qnil;
96
+ }
97
+
98
+ VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
99
+ rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
100
+ return Qnil;
101
+ }
102
+
103
+ VALUE default_write_map_end(VALUE protocol) {
104
+ rb_funcall(protocol, write_map_end_method_id, 0);
105
+ return Qnil;
106
+ }
107
+
108
+ VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
109
+ rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
110
+ return Qnil;
111
+ }
112
+
113
+ VALUE default_write_struct_end(VALUE protocol) {
114
+ rb_funcall(protocol, write_struct_end_method_id, 0);
115
+ return Qnil;
116
+ }
117
+
118
+ VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
119
+ rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
120
+ return Qnil;
121
+ }
122
+
123
+ VALUE default_write_field_end(VALUE protocol) {
124
+ rb_funcall(protocol, write_field_end_method_id, 0);
125
+ return Qnil;
126
+ }
127
+
128
+ VALUE default_write_field_stop(VALUE protocol) {
129
+ rb_funcall(protocol, write_field_stop_method_id, 0);
130
+ return Qnil;
131
+ }
132
+
133
+ VALUE default_read_field_begin(VALUE protocol) {
134
+ return rb_funcall(protocol, read_field_begin_method_id, 0);
135
+ }
136
+
137
+ VALUE default_read_field_end(VALUE protocol) {
138
+ return rb_funcall(protocol, read_field_end_method_id, 0);
139
+ }
140
+
141
+ VALUE default_read_map_begin(VALUE protocol) {
142
+ return rb_funcall(protocol, read_map_begin_method_id, 0);
143
+ }
144
+
145
+ VALUE default_read_map_end(VALUE protocol) {
146
+ return rb_funcall(protocol, read_map_end_method_id, 0);
147
+ }
148
+
149
+ VALUE default_read_list_begin(VALUE protocol) {
150
+ return rb_funcall(protocol, read_list_begin_method_id, 0);
151
+ }
152
+
153
+ VALUE default_read_list_end(VALUE protocol) {
154
+ return rb_funcall(protocol, read_list_end_method_id, 0);
155
+ }
156
+
157
+ VALUE default_read_set_begin(VALUE protocol) {
158
+ return rb_funcall(protocol, read_set_begin_method_id, 0);
159
+ }
160
+
161
+ VALUE default_read_set_end(VALUE protocol) {
162
+ return rb_funcall(protocol, read_set_end_method_id, 0);
163
+ }
164
+
165
+ VALUE default_read_byte(VALUE protocol) {
166
+ return rb_funcall(protocol, read_byte_method_id, 0);
167
+ }
168
+
169
+ VALUE default_read_bool(VALUE protocol) {
170
+ return rb_funcall(protocol, read_bool_method_id, 0);
171
+ }
172
+
173
+ VALUE default_read_i16(VALUE protocol) {
174
+ return rb_funcall(protocol, read_i16_method_id, 0);
175
+ }
176
+
177
+ VALUE default_read_i32(VALUE protocol) {
178
+ return rb_funcall(protocol, read_i32_method_id, 0);
179
+ }
180
+
181
+ VALUE default_read_i64(VALUE protocol) {
182
+ return rb_funcall(protocol, read_i64_method_id, 0);
183
+ }
184
+
185
+ VALUE default_read_double(VALUE protocol) {
186
+ return rb_funcall(protocol, read_double_method_id, 0);
187
+ }
188
+
189
+ VALUE default_read_string(VALUE protocol) {
190
+ return rb_funcall(protocol, read_string_method_id, 0);
191
+ }
192
+
193
+ VALUE default_read_struct_begin(VALUE protocol) {
194
+ return rb_funcall(protocol, read_struct_begin_method_id, 0);
195
+ }
196
+
197
+ VALUE default_read_struct_end(VALUE protocol) {
198
+ return rb_funcall(protocol, read_struct_end_method_id, 0);
199
+ }
200
+
201
+ // end default protocol methods
202
+
203
+ static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
204
+ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
205
+ static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
206
+
207
+ VALUE get_field_value(VALUE obj, VALUE field_name) {
208
+ char name_buf[RSTRING_LEN(field_name) + 2];
209
+
210
+ name_buf[0] = '@';
211
+ strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
212
+
213
+ VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
214
+
215
+ return value;
216
+ }
217
+
218
+ static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
219
+ int sz, i;
220
+
221
+ if (ttype == TTYPE_MAP) {
222
+ VALUE keys;
223
+ VALUE key;
224
+ VALUE val;
225
+
226
+ Check_Type(value, T_HASH);
227
+
228
+ VALUE key_info = rb_hash_aref(field_info, key_sym);
229
+ VALUE keytype_value = rb_hash_aref(key_info, type_sym);
230
+ int keytype = FIX2INT(keytype_value);
231
+
232
+ VALUE value_info = rb_hash_aref(field_info, value_sym);
233
+ VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
234
+ int valuetype = FIX2INT(valuetype_value);
235
+
236
+ keys = rb_funcall(value, keys_method_id, 0);
237
+
238
+ sz = RARRAY_LEN(keys);
239
+
240
+ default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
241
+
242
+ for (i = 0; i < sz; i++) {
243
+ key = rb_ary_entry(keys, i);
244
+ val = rb_hash_aref(value, key);
245
+
246
+ if (IS_CONTAINER(keytype)) {
247
+ write_container(keytype, key_info, key, protocol);
248
+ } else {
249
+ write_anything(keytype, key, protocol, key_info);
250
+ }
251
+
252
+ if (IS_CONTAINER(valuetype)) {
253
+ write_container(valuetype, value_info, val, protocol);
254
+ } else {
255
+ write_anything(valuetype, val, protocol, value_info);
256
+ }
257
+ }
258
+
259
+ default_write_map_end(protocol);
260
+ } else if (ttype == TTYPE_LIST) {
261
+ Check_Type(value, T_ARRAY);
262
+
263
+ sz = RARRAY_LEN(value);
264
+
265
+ VALUE element_type_info = rb_hash_aref(field_info, element_sym);
266
+ VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
267
+ int element_type = FIX2INT(element_type_value);
268
+
269
+ default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
270
+ for (i = 0; i < sz; ++i) {
271
+ VALUE val = rb_ary_entry(value, i);
272
+ if (IS_CONTAINER(element_type)) {
273
+ write_container(element_type, element_type_info, val, protocol);
274
+ } else {
275
+ write_anything(element_type, val, protocol, element_type_info);
276
+ }
277
+ }
278
+ default_write_list_end(protocol);
279
+ } else if (ttype == TTYPE_SET) {
280
+ VALUE items;
281
+
282
+ if (TYPE(value) == T_ARRAY) {
283
+ items = value;
284
+ } else {
285
+ if (rb_cSet == CLASS_OF(value)) {
286
+ items = rb_funcall(value, entries_method_id, 0);
287
+ } else {
288
+ Check_Type(value, T_HASH);
289
+ items = rb_funcall(value, keys_method_id, 0);
290
+ }
291
+ }
292
+
293
+ sz = RARRAY_LEN(items);
294
+
295
+ VALUE element_type_info = rb_hash_aref(field_info, element_sym);
296
+ VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
297
+ int element_type = FIX2INT(element_type_value);
298
+
299
+ default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
300
+
301
+ for (i = 0; i < sz; i++) {
302
+ VALUE val = rb_ary_entry(items, i);
303
+ if (IS_CONTAINER(element_type)) {
304
+ write_container(element_type, element_type_info, val, protocol);
305
+ } else {
306
+ write_anything(element_type, val, protocol, element_type_info);
307
+ }
308
+ }
309
+
310
+ default_write_set_end(protocol);
311
+ } else {
312
+ rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
313
+ }
314
+ }
315
+
316
+ static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
317
+ if (ttype == TTYPE_BOOL) {
318
+ default_write_bool(protocol, value);
319
+ } else if (ttype == TTYPE_BYTE) {
320
+ default_write_byte(protocol, value);
321
+ } else if (ttype == TTYPE_I16) {
322
+ default_write_i16(protocol, value);
323
+ } else if (ttype == TTYPE_I32) {
324
+ default_write_i32(protocol, value);
325
+ } else if (ttype == TTYPE_I64) {
326
+ default_write_i64(protocol, value);
327
+ } else if (ttype == TTYPE_DOUBLE) {
328
+ default_write_double(protocol, value);
329
+ } else if (ttype == TTYPE_STRING) {
330
+ default_write_string(protocol, value);
331
+ } else if (IS_CONTAINER(ttype)) {
332
+ write_container(ttype, field_info, value, protocol);
333
+ } else if (ttype == TTYPE_STRUCT) {
334
+ if (rb_obj_is_kind_of(value, thrift_union_class)) {
335
+ rb_thrift_union_write(value, protocol);
336
+ } else {
337
+ rb_thrift_struct_write(value, protocol);
338
+ }
339
+ } else {
340
+ rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
341
+ }
342
+ }
343
+
344
+ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
345
+ // call validate
346
+ rb_funcall(self, validate_method_id, 0);
347
+
348
+ // write struct begin
349
+ default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
350
+
351
+ // iterate through all the fields here
352
+ VALUE struct_fields = STRUCT_FIELDS(self);
353
+ VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
354
+
355
+ int i = 0;
356
+ for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
357
+ VALUE field_id = rb_ary_entry(sorted_field_ids, i);
358
+
359
+ VALUE field_info = rb_hash_aref(struct_fields, field_id);
360
+
361
+ VALUE ttype_value = rb_hash_aref(field_info, type_sym);
362
+ int ttype = FIX2INT(ttype_value);
363
+ VALUE field_name = rb_hash_aref(field_info, name_sym);
364
+
365
+ VALUE field_value = get_field_value(self, field_name);
366
+
367
+ if (!NIL_P(field_value)) {
368
+ default_write_field_begin(protocol, field_name, ttype_value, field_id);
369
+
370
+ write_anything(ttype, field_value, protocol, field_info);
371
+
372
+ default_write_field_end(protocol);
373
+ }
374
+ }
375
+
376
+ default_write_field_stop(protocol);
377
+
378
+ // write struct end
379
+ default_write_struct_end(protocol);
380
+
381
+ return Qnil;
382
+ }
383
+
384
+ //-------------------------------------------
385
+ // Reading section
386
+ //-------------------------------------------
387
+
388
+ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
389
+ static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
390
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
391
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
392
+
393
+ static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
394
+ char name_buf[RSTRING_LEN(field_name) + 2];
395
+
396
+ name_buf[0] = '@';
397
+ strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
398
+
399
+ rb_ivar_set(obj, rb_intern(name_buf), value);
400
+ }
401
+
402
+ // Helper method to skip the contents of a map (assumes the map header has been read).
403
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
404
+ int i;
405
+ for (i = 0; i < size; i++) {
406
+ rb_funcall(protocol, skip_method_id, 1, key_type_value);
407
+ rb_funcall(protocol, skip_method_id, 1, value_type_value);
408
+ }
409
+ }
410
+
411
+ // Helper method to skip the contents of a list or set (assumes the list/set header has been read).
412
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
413
+ int i;
414
+ for (i = 0; i < size; i++) {
415
+ rb_funcall(protocol, skip_method_id, 1, element_type_value);
416
+ }
417
+ }
418
+
419
+ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
420
+ VALUE result = Qnil;
421
+
422
+ if (ttype == TTYPE_BOOL) {
423
+ result = default_read_bool(protocol);
424
+ } else if (ttype == TTYPE_BYTE) {
425
+ result = default_read_byte(protocol);
426
+ } else if (ttype == TTYPE_I16) {
427
+ result = default_read_i16(protocol);
428
+ } else if (ttype == TTYPE_I32) {
429
+ result = default_read_i32(protocol);
430
+ } else if (ttype == TTYPE_I64) {
431
+ result = default_read_i64(protocol);
432
+ } else if (ttype == TTYPE_STRING) {
433
+ result = default_read_string(protocol);
434
+ } else if (ttype == TTYPE_DOUBLE) {
435
+ result = default_read_double(protocol);
436
+ } else if (ttype == TTYPE_STRUCT) {
437
+ VALUE klass = rb_hash_aref(field_info, class_sym);
438
+ result = rb_class_new_instance(0, NULL, klass);
439
+
440
+ if (rb_obj_is_kind_of(result, thrift_union_class)) {
441
+ rb_thrift_union_read(result, protocol);
442
+ } else {
443
+ rb_thrift_struct_read(result, protocol);
444
+ }
445
+ } else if (ttype == TTYPE_MAP) {
446
+ int i;
447
+
448
+ VALUE map_header = default_read_map_begin(protocol);
449
+ int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
450
+ int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
451
+ int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
452
+
453
+ // Check the declared key and value types against the expected ones and skip the map contents
454
+ // if the types don't match.
455
+ VALUE key_info = rb_hash_aref(field_info, key_sym);
456
+ VALUE value_info = rb_hash_aref(field_info, value_sym);
457
+
458
+ if (!NIL_P(key_info) && !NIL_P(value_info)) {
459
+ int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
460
+ int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
461
+ if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
462
+ result = rb_hash_new();
463
+
464
+ for (i = 0; i < num_entries; ++i) {
465
+ VALUE key, val;
466
+
467
+ key = read_anything(protocol, key_ttype, key_info);
468
+ val = read_anything(protocol, value_ttype, value_info);
469
+
470
+ rb_hash_aset(result, key, val);
471
+ }
472
+ } else {
473
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
474
+ }
475
+ } else {
476
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
477
+ }
478
+
479
+ default_read_map_end(protocol);
480
+ } else if (ttype == TTYPE_LIST) {
481
+ int i;
482
+
483
+ VALUE list_header = default_read_list_begin(protocol);
484
+ int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
485
+ int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
486
+
487
+ // Check the declared element type against the expected one and skip the list contents
488
+ // if the types don't match.
489
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
490
+ if (!NIL_P(element_info)) {
491
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
492
+ if (specified_element_type == element_ttype) {
493
+ result = rb_ary_new2(num_elements);
494
+
495
+ for (i = 0; i < num_elements; ++i) {
496
+ rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
497
+ }
498
+ } else {
499
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
500
+ }
501
+ } else {
502
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
503
+ }
504
+
505
+ default_read_list_end(protocol);
506
+ } else if (ttype == TTYPE_SET) {
507
+ VALUE items;
508
+ int i;
509
+
510
+ VALUE set_header = default_read_set_begin(protocol);
511
+ int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
512
+ int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
513
+
514
+ // Check the declared element type against the expected one and skip the set contents
515
+ // if the types don't match.
516
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
517
+ if (!NIL_P(element_info)) {
518
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
519
+ if (specified_element_type == element_ttype) {
520
+ items = rb_ary_new2(num_elements);
521
+
522
+ for (i = 0; i < num_elements; ++i) {
523
+ rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
524
+ }
525
+
526
+ result = rb_class_new_instance(1, &items, rb_cSet);
527
+ } else {
528
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
529
+ }
530
+ } else {
531
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
532
+ }
533
+
534
+ default_read_set_end(protocol);
535
+ } else {
536
+ rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
537
+ }
538
+
539
+ return result;
540
+ }
541
+
542
+ static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
543
+ // read struct begin
544
+ default_read_struct_begin(protocol);
545
+
546
+ VALUE struct_fields = STRUCT_FIELDS(self);
547
+
548
+ // read each field
549
+ while (true) {
550
+ VALUE field_header = default_read_field_begin(protocol);
551
+ VALUE field_type_value = rb_ary_entry(field_header, 1);
552
+ int field_type = FIX2INT(field_type_value);
553
+
554
+ if (field_type == TTYPE_STOP) {
555
+ break;
556
+ }
557
+
558
+ // make sure we got a type we expected
559
+ VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
560
+
561
+ if (!NIL_P(field_info)) {
562
+ int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
563
+ if (field_type == specified_type) {
564
+ // read the value
565
+ VALUE name = rb_hash_aref(field_info, name_sym);
566
+ set_field_value(self, name, read_anything(protocol, field_type, field_info));
567
+ } else {
568
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
569
+ }
570
+ } else {
571
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
572
+ }
573
+
574
+ // read field end
575
+ default_read_field_end(protocol);
576
+ }
577
+
578
+ // read struct end
579
+ default_read_struct_end(protocol);
580
+
581
+ // call validate
582
+ rb_funcall(self, validate_method_id, 0);
583
+
584
+ return Qnil;
585
+ }
586
+
587
+
588
+ // --------------------------------
589
+ // Union section
590
+ // --------------------------------
591
+
592
+ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
593
+ // read struct begin
594
+ default_read_struct_begin(protocol);
595
+
596
+ VALUE struct_fields = STRUCT_FIELDS(self);
597
+
598
+ VALUE field_header = default_read_field_begin(protocol);
599
+ VALUE field_type_value = rb_ary_entry(field_header, 1);
600
+ int field_type = FIX2INT(field_type_value);
601
+
602
+ // make sure we got a type we expected
603
+ VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
604
+
605
+ if (!NIL_P(field_info)) {
606
+ int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
607
+ if (field_type == specified_type) {
608
+ // read the value
609
+ VALUE name = rb_hash_aref(field_info, name_sym);
610
+ rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
611
+ rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
612
+ } else {
613
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
614
+ }
615
+ } else {
616
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
617
+ }
618
+
619
+ // read field end
620
+ default_read_field_end(protocol);
621
+
622
+ field_header = default_read_field_begin(protocol);
623
+ field_type_value = rb_ary_entry(field_header, 1);
624
+ field_type = FIX2INT(field_type_value);
625
+
626
+ if (field_type != TTYPE_STOP) {
627
+ rb_raise(rb_eRuntimeError, "too many fields in union!");
628
+ }
629
+
630
+ // read field end
631
+ default_read_field_end(protocol);
632
+
633
+ // read struct end
634
+ default_read_struct_end(protocol);
635
+
636
+ // call validate
637
+ rb_funcall(self, validate_method_id, 0);
638
+
639
+ return Qnil;
640
+ }
641
+
642
+ static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
643
+ // call validate
644
+ rb_funcall(self, validate_method_id, 0);
645
+
646
+ // write struct begin
647
+ default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
648
+
649
+ VALUE struct_fields = STRUCT_FIELDS(self);
650
+
651
+ VALUE setfield = rb_ivar_get(self, setfield_id);
652
+ VALUE setvalue = rb_ivar_get(self, setvalue_id);
653
+ VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
654
+
655
+ VALUE field_info = rb_hash_aref(struct_fields, field_id);
656
+
657
+ VALUE ttype_value = rb_hash_aref(field_info, type_sym);
658
+ int ttype = FIX2INT(ttype_value);
659
+
660
+ default_write_field_begin(protocol, setfield, ttype_value, field_id);
661
+
662
+ write_anything(ttype, setvalue, protocol, field_info);
663
+
664
+ default_write_field_end(protocol);
665
+
666
+ default_write_field_stop(protocol);
667
+
668
+ // write struct end
669
+ default_write_struct_end(protocol);
670
+
671
+ return Qnil;
672
+ }
673
+
674
+ void Init_struct() {
675
+ VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
676
+
677
+ rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
678
+ rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
679
+
680
+ thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
681
+
682
+ rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
683
+ rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
684
+
685
+ setfield_id = rb_intern("@setfield");
686
+ setvalue_id = rb_intern("@value");
687
+
688
+ to_s_method_id = rb_intern("to_s");
689
+ name_to_id_method_id = rb_intern("name_to_id");
690
+ sorted_field_ids_method_id = rb_intern("sorted_field_ids");
691
+ }