blob: e3aa855ed319e8b074e79be38d445334f7f66620 [file] [log] [blame]
Kevin Clark916f3532009-03-20 04:21:39 +00001/**
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
Bryan Duxbury09d13c22010-08-11 18:37:25 +000020#include "struct.h"
21#include "constants.h"
Bryan Duxbury6b771d22009-03-26 04:55:34 +000022#include "macros.h"
Jake Farrelld5df77a2011-11-06 17:43:44 +000023#include "strlcpy.h"
Bryan Duxburyc0166282009-02-02 00:48:17 +000024
Bryan Duxbury33e190c2010-02-16 21:19:01 +000025VALUE thrift_union_class;
26
27ID setfield_id;
28ID setvalue_id;
29
30ID to_s_method_id;
31ID name_to_id_method_id;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +000032static ID sorted_field_ids_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000033
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
43VALUE default_write_bool(VALUE protocol, VALUE value) {
44 rb_funcall(protocol, write_boolean_method_id, 1, value);
45 return Qnil;
46}
47
48VALUE default_write_byte(VALUE protocol, VALUE value) {
49 rb_funcall(protocol, write_byte_method_id, 1, value);
50 return Qnil;
51}
52
53VALUE default_write_i16(VALUE protocol, VALUE value) {
54 rb_funcall(protocol, write_i16_method_id, 1, value);
55 return Qnil;
56}
57
58VALUE default_write_i32(VALUE protocol, VALUE value) {
59 rb_funcall(protocol, write_i32_method_id, 1, value);
60 return Qnil;
61}
62
63VALUE default_write_i64(VALUE protocol, VALUE value) {
64 rb_funcall(protocol, write_i64_method_id, 1, value);
65 return Qnil;
66}
67
68VALUE default_write_double(VALUE protocol, VALUE value) {
69 rb_funcall(protocol, write_double_method_id, 1, value);
70 return Qnil;
71}
72
73VALUE default_write_string(VALUE protocol, VALUE value) {
74 rb_funcall(protocol, write_string_method_id, 1, value);
75 return Qnil;
76}
77
henrique8a2bab32014-07-16 20:10:57 +020078VALUE default_write_binary(VALUE protocol, VALUE value) {
79 rb_funcall(protocol, write_binary_method_id, 1, value);
80 return Qnil;
81}
82
Bryan Duxburyc0166282009-02-02 00:48:17 +000083VALUE 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
88VALUE default_write_list_end(VALUE protocol) {
89 rb_funcall(protocol, write_list_end_method_id, 0);
90 return Qnil;
91}
92
93VALUE 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
98VALUE default_write_set_end(VALUE protocol) {
99 rb_funcall(protocol, write_set_end_method_id, 0);
100 return Qnil;
101}
102
103VALUE 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
108VALUE default_write_map_end(VALUE protocol) {
109 rb_funcall(protocol, write_map_end_method_id, 0);
110 return Qnil;
111}
112
113VALUE 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
118VALUE default_write_struct_end(VALUE protocol) {
119 rb_funcall(protocol, write_struct_end_method_id, 0);
120 return Qnil;
121}
122
123VALUE 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
128VALUE default_write_field_end(VALUE protocol) {
129 rb_funcall(protocol, write_field_end_method_id, 0);
130 return Qnil;
131}
132
133VALUE default_write_field_stop(VALUE protocol) {
134 rb_funcall(protocol, write_field_stop_method_id, 0);
135 return Qnil;
136}
137
138VALUE default_read_field_begin(VALUE protocol) {
139 return rb_funcall(protocol, read_field_begin_method_id, 0);
140}
141
142VALUE default_read_field_end(VALUE protocol) {
143 return rb_funcall(protocol, read_field_end_method_id, 0);
144}
145
146VALUE default_read_map_begin(VALUE protocol) {
147 return rb_funcall(protocol, read_map_begin_method_id, 0);
148}
149
150VALUE default_read_map_end(VALUE protocol) {
151 return rb_funcall(protocol, read_map_end_method_id, 0);
152}
153
154VALUE default_read_list_begin(VALUE protocol) {
155 return rb_funcall(protocol, read_list_begin_method_id, 0);
156}
157
158VALUE default_read_list_end(VALUE protocol) {
159 return rb_funcall(protocol, read_list_end_method_id, 0);
160}
161
162VALUE default_read_set_begin(VALUE protocol) {
163 return rb_funcall(protocol, read_set_begin_method_id, 0);
164}
165
166VALUE default_read_set_end(VALUE protocol) {
167 return rb_funcall(protocol, read_set_end_method_id, 0);
168}
169
170VALUE default_read_byte(VALUE protocol) {
171 return rb_funcall(protocol, read_byte_method_id, 0);
172}
173
174VALUE default_read_bool(VALUE protocol) {
175 return rb_funcall(protocol, read_bool_method_id, 0);
176}
177
178VALUE default_read_i16(VALUE protocol) {
179 return rb_funcall(protocol, read_i16_method_id, 0);
180}
181
182VALUE default_read_i32(VALUE protocol) {
183 return rb_funcall(protocol, read_i32_method_id, 0);
184}
185
186VALUE default_read_i64(VALUE protocol) {
187 return rb_funcall(protocol, read_i64_method_id, 0);
188}
189
190VALUE default_read_double(VALUE protocol) {
191 return rb_funcall(protocol, read_double_method_id, 0);
192}
193
194VALUE default_read_string(VALUE protocol) {
195 return rb_funcall(protocol, read_string_method_id, 0);
196}
197
henrique8a2bab32014-07-16 20:10:57 +0200198VALUE default_read_binary(VALUE protocol) {
199 return rb_funcall(protocol, read_binary_method_id, 0);
200}
201
Bryan Duxburyc0166282009-02-02 00:48:17 +0000202VALUE default_read_struct_begin(VALUE protocol) {
203 return rb_funcall(protocol, read_struct_begin_method_id, 0);
204}
205
206VALUE default_read_struct_end(VALUE protocol) {
207 return rb_funcall(protocol, read_struct_end_method_id, 0);
208}
209
Bryan Duxburyc0166282009-02-02 00:48:17 +0000210// end default protocol methods
211
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000212static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000213static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
214static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
215
216VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000217 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000218
Bryan Duxburyc0166282009-02-02 00:48:17 +0000219 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000220 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000221
222 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000223
Bryan Duxburyc0166282009-02-02 00:48:17 +0000224 return value;
225}
226
227static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
228 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000229
Bryan Duxburyc0166282009-02-02 00:48:17 +0000230 if (ttype == TTYPE_MAP) {
231 VALUE keys;
232 VALUE key;
233 VALUE val;
234
235 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000236
Bryan Duxburyc0166282009-02-02 00:48:17 +0000237 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000240
Bryan Duxburyc0166282009-02-02 00:48:17 +0000241 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000244
Bryan Duxburyc0166282009-02-02 00:48:17 +0000245 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000246
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000247 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000248
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000249 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000250
Bryan Duxburyc0166282009-02-02 00:48:17 +0000251 for (i = 0; i < sz; i++) {
252 key = rb_ary_entry(keys, i);
253 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000254
Bryan Duxburyc0166282009-02-02 00:48:17 +0000255 if (IS_CONTAINER(keytype)) {
256 write_container(keytype, key_info, key, protocol);
257 } else {
258 write_anything(keytype, key, protocol, key_info);
259 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000260
Bryan Duxburyc0166282009-02-02 00:48:17 +0000261 if (IS_CONTAINER(valuetype)) {
262 write_container(valuetype, value_info, val, protocol);
263 } else {
264 write_anything(valuetype, val, protocol, value_info);
265 }
266 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000267
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000268 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000269 } else if (ttype == TTYPE_LIST) {
270 Check_Type(value, T_ARRAY);
271
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000272 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000273
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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000277
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000278 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000279 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 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000287 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000288 } else if (ttype == TTYPE_SET) {
289 VALUE items;
290
291 if (TYPE(value) == T_ARRAY) {
292 items = value;
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000293 } else {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000294 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
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000302 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000303
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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000307
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000308 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000309
Bryan Duxburyc0166282009-02-02 00:48:17 +0000310 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 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000318
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000319 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000320 } else {
321 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
322 }
323}
324
325static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
326 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000327 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000328 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000329 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000330 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000331 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000332 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000333 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000334 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000335 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000336 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000337 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000338 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200339 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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000345 } else if (IS_CONTAINER(ttype)) {
346 write_container(ttype, field_info, value, protocol);
347 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000348 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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000353 } else {
354 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
355 }
356}
357
358static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
359 // call validate
360 rb_funcall(self, validate_method_id, 0);
361
Bryan Duxburyc0166282009-02-02 00:48:17 +0000362 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000363 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000364
Bryan Duxburyc0166282009-02-02 00:48:17 +0000365 // iterate through all the fields here
366 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000367 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000368
Bryan Duxburyc0166282009-02-02 00:48:17 +0000369 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000370 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
371 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000372
Bryan Duxburyc0166282009-02-02 00:48:17 +0000373 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000378
Bryan Duxburyc0166282009-02-02 00:48:17 +0000379 VALUE field_value = get_field_value(self, field_name);
380
381 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000382 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000383
Bryan Duxburyc0166282009-02-02 00:48:17 +0000384 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000385
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000386 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000387 }
388 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000389
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000390 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000391
Bryan Duxburyc0166282009-02-02 00:48:17 +0000392 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000393 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000394
Bryan Duxburyc0166282009-02-02 00:48:17 +0000395 return Qnil;
396}
397
398//-------------------------------------------
399// Reading section
400//-------------------------------------------
401
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000402static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000403static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000404static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
405static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000406
407static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000408 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000409
410 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000411 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000412
413 rb_ivar_set(obj, rb_intern(name_buf), value);
414}
415
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000416// Helper method to skip the contents of a map (assumes the map header has been read).
417static 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).
426static 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
Bryan Duxburyc0166282009-02-02 00:48:17 +0000433static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
434 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000435
Bryan Duxburyc0166282009-02-02 00:48:17 +0000436 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000437 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000438 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000439 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000440 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000441 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000442 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000443 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000444 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000445 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000446 } else if (ttype == TTYPE_STRING) {
henrique8a2bab32014-07-16 20:10:57 +0200447 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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000453 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000454 result = default_read_double(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000455 } else if (ttype == TTYPE_STRUCT) {
456 VALUE klass = rb_hash_aref(field_info, class_sym);
457 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000458
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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000464 } else if (ttype == TTYPE_MAP) {
465 int i;
466
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000467 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000468 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));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000471
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000472 // Check the declared key and value types against the expected ones and skip the map contents
473 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000474 VALUE key_info = rb_hash_aref(field_info, key_sym);
475 VALUE value_info = rb_hash_aref(field_info, value_sym);
476
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000477 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));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000480 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000481 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000482
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000483 for (i = 0; i < num_entries; ++i) {
484 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000485
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000486 key = read_anything(protocol, key_ttype, key_info);
487 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000488
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000489 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000496 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000497
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000498 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000499 } else if (ttype == TTYPE_LIST) {
500 int i;
501
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000502 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000503 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
504 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000505
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000506 // 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000522 }
523
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000524 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000525 } else if (ttype == TTYPE_SET) {
526 VALUE items;
527 int i;
528
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000529 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000530 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
531 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000532
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000533 // 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000551 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000552
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000553 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000554 } else {
555 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
556 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000557
Bryan Duxburyc0166282009-02-02 00:48:17 +0000558 return result;
559}
560
561static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000562 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000563 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000564
565 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000566
Bryan Duxburyc0166282009-02-02 00:48:17 +0000567 // read each field
568 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000569 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000570 VALUE field_type_value = rb_ary_entry(field_header, 1);
571 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000572
Bryan Duxburyc0166282009-02-02 00:48:17 +0000573 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 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000592
Bryan Duxburyc0166282009-02-02 00:48:17 +0000593 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000594 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000595 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000596
Bryan Duxburyc0166282009-02-02 00:48:17 +0000597 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000598 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000599
Bryan Duxbury834895d2009-10-15 01:20:34 +0000600 // call validate
601 rb_funcall(self, validate_method_id, 0);
602
Bryan Duxburyc0166282009-02-02 00:48:17 +0000603 return Qnil;
604}
605
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000606
607// --------------------------------
608// Union section
609// --------------------------------
610
611static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
612 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000613 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000614
615 VALUE struct_fields = STRUCT_FIELDS(self);
616
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000617 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000618 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);
Roger Meier02405722014-01-12 23:29:11 +0100629 rb_iv_set(self, "@setfield", rb_str_intern(name));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000630 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
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000639 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000640
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000641 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000642 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
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000649 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000650 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000651
652 // call validate
653 rb_funcall(self, validate_method_id, 0);
654
655 return Qnil;
656}
657
658static 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
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000663 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000664
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
Joe Ennever5b15f8c2015-08-31 19:20:36 +0000673 if(NIL_P(field_info)) {
674 rb_raise(rb_eRuntimeError, "set_field is not valid for this union!");
675 }
676
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000677 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
678 int ttype = FIX2INT(ttype_value);
679
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000680 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000681
682 write_anything(ttype, setvalue, protocol, field_info);
683
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000684 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000685
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000686 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000687
688 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000689 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000690
691 return Qnil;
692}
693
Bryan Duxburyc0166282009-02-02 00:48:17 +0000694void Init_struct() {
695 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000696
Bryan Duxburyc0166282009-02-02 00:48:17 +0000697 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
698 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000699
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000700 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
701
702 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
703 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
704
705 setfield_id = rb_intern("@setfield");
706 setvalue_id = rb_intern("@value");
707
708 to_s_method_id = rb_intern("to_s");
709 name_to_id_method_id = rb_intern("name_to_id");
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000710 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Bryan Duxbury65073e52010-02-23 15:46:46 +0000711}