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