blob: 313da4c806307c7bb7acd47bf4a7acba33b4244a [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
78VALUE 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
83VALUE default_write_list_end(VALUE protocol) {
84 rb_funcall(protocol, write_list_end_method_id, 0);
85 return Qnil;
86}
87
88VALUE 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
93VALUE default_write_set_end(VALUE protocol) {
94 rb_funcall(protocol, write_set_end_method_id, 0);
95 return Qnil;
96}
97
98VALUE 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
103VALUE default_write_map_end(VALUE protocol) {
104 rb_funcall(protocol, write_map_end_method_id, 0);
105 return Qnil;
106}
107
108VALUE 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
113VALUE default_write_struct_end(VALUE protocol) {
114 rb_funcall(protocol, write_struct_end_method_id, 0);
115 return Qnil;
116}
117
118VALUE 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
123VALUE default_write_field_end(VALUE protocol) {
124 rb_funcall(protocol, write_field_end_method_id, 0);
125 return Qnil;
126}
127
128VALUE default_write_field_stop(VALUE protocol) {
129 rb_funcall(protocol, write_field_stop_method_id, 0);
130 return Qnil;
131}
132
133VALUE default_read_field_begin(VALUE protocol) {
134 return rb_funcall(protocol, read_field_begin_method_id, 0);
135}
136
137VALUE default_read_field_end(VALUE protocol) {
138 return rb_funcall(protocol, read_field_end_method_id, 0);
139}
140
141VALUE default_read_map_begin(VALUE protocol) {
142 return rb_funcall(protocol, read_map_begin_method_id, 0);
143}
144
145VALUE default_read_map_end(VALUE protocol) {
146 return rb_funcall(protocol, read_map_end_method_id, 0);
147}
148
149VALUE default_read_list_begin(VALUE protocol) {
150 return rb_funcall(protocol, read_list_begin_method_id, 0);
151}
152
153VALUE default_read_list_end(VALUE protocol) {
154 return rb_funcall(protocol, read_list_end_method_id, 0);
155}
156
157VALUE default_read_set_begin(VALUE protocol) {
158 return rb_funcall(protocol, read_set_begin_method_id, 0);
159}
160
161VALUE default_read_set_end(VALUE protocol) {
162 return rb_funcall(protocol, read_set_end_method_id, 0);
163}
164
165VALUE default_read_byte(VALUE protocol) {
166 return rb_funcall(protocol, read_byte_method_id, 0);
167}
168
169VALUE default_read_bool(VALUE protocol) {
170 return rb_funcall(protocol, read_bool_method_id, 0);
171}
172
173VALUE default_read_i16(VALUE protocol) {
174 return rb_funcall(protocol, read_i16_method_id, 0);
175}
176
177VALUE default_read_i32(VALUE protocol) {
178 return rb_funcall(protocol, read_i32_method_id, 0);
179}
180
181VALUE default_read_i64(VALUE protocol) {
182 return rb_funcall(protocol, read_i64_method_id, 0);
183}
184
185VALUE default_read_double(VALUE protocol) {
186 return rb_funcall(protocol, read_double_method_id, 0);
187}
188
189VALUE default_read_string(VALUE protocol) {
190 return rb_funcall(protocol, read_string_method_id, 0);
191}
192
193VALUE default_read_struct_begin(VALUE protocol) {
194 return rb_funcall(protocol, read_struct_begin_method_id, 0);
195}
196
197VALUE default_read_struct_end(VALUE protocol) {
198 return rb_funcall(protocol, read_struct_end_method_id, 0);
199}
200
Bryan Duxburyc0166282009-02-02 00:48:17 +0000201// end default protocol methods
202
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000203static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000204static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
205static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
206
207VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000208 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000209
Bryan Duxburyc0166282009-02-02 00:48:17 +0000210 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000211 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000212
213 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000214
Bryan Duxburyc0166282009-02-02 00:48:17 +0000215 return value;
216}
217
218static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
219 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000220
Bryan Duxburyc0166282009-02-02 00:48:17 +0000221 if (ttype == TTYPE_MAP) {
222 VALUE keys;
223 VALUE key;
224 VALUE val;
225
226 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000227
Bryan Duxburyc0166282009-02-02 00:48:17 +0000228 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000231
Bryan Duxburyc0166282009-02-02 00:48:17 +0000232 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000235
Bryan Duxburyc0166282009-02-02 00:48:17 +0000236 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000237
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000238 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000239
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000240 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000241
Bryan Duxburyc0166282009-02-02 00:48:17 +0000242 for (i = 0; i < sz; i++) {
243 key = rb_ary_entry(keys, i);
244 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000245
Bryan Duxburyc0166282009-02-02 00:48:17 +0000246 if (IS_CONTAINER(keytype)) {
247 write_container(keytype, key_info, key, protocol);
248 } else {
249 write_anything(keytype, key, protocol, key_info);
250 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000251
Bryan Duxburyc0166282009-02-02 00:48:17 +0000252 if (IS_CONTAINER(valuetype)) {
253 write_container(valuetype, value_info, val, protocol);
254 } else {
255 write_anything(valuetype, val, protocol, value_info);
256 }
257 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000258
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000259 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000260 } else if (ttype == TTYPE_LIST) {
261 Check_Type(value, T_ARRAY);
262
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000263 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000264
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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000268
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000269 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000270 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 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000278 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000279 } 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
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000293 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000294
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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000298
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000299 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000300
Bryan Duxburyc0166282009-02-02 00:48:17 +0000301 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 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000309
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000310 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000311 } else {
312 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
313 }
314}
315
316static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
317 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000318 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000319 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000320 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000321 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000322 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000323 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000324 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000325 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000326 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000327 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000328 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000329 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000330 default_write_string(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000331 } else if (IS_CONTAINER(ttype)) {
332 write_container(ttype, field_info, value, protocol);
333 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000334 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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000339 } else {
340 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
341 }
342}
343
344static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
345 // call validate
346 rb_funcall(self, validate_method_id, 0);
347
Bryan Duxburyc0166282009-02-02 00:48:17 +0000348 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000349 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000350
Bryan Duxburyc0166282009-02-02 00:48:17 +0000351 // iterate through all the fields here
352 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000353 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000354
Bryan Duxburyc0166282009-02-02 00:48:17 +0000355 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000356 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
357 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000358
Bryan Duxburyc0166282009-02-02 00:48:17 +0000359 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);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000364
Bryan Duxburyc0166282009-02-02 00:48:17 +0000365 VALUE field_value = get_field_value(self, field_name);
366
367 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000368 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000369
Bryan Duxburyc0166282009-02-02 00:48:17 +0000370 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000371
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000372 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000373 }
374 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000375
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000376 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000377
Bryan Duxburyc0166282009-02-02 00:48:17 +0000378 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000379 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000380
Bryan Duxburyc0166282009-02-02 00:48:17 +0000381 return Qnil;
382}
383
384//-------------------------------------------
385// Reading section
386//-------------------------------------------
387
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000388static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000389static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000390static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
391static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000392
393static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000394 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000395
396 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000397 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000398
399 rb_ivar_set(obj, rb_intern(name_buf), value);
400}
401
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000402// Helper method to skip the contents of a map (assumes the map header has been read).
403static 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).
412static 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
Bryan Duxburyc0166282009-02-02 00:48:17 +0000419static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
420 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000421
Bryan Duxburyc0166282009-02-02 00:48:17 +0000422 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000423 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000424 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000425 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000426 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000427 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000428 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000429 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000430 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000431 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000432 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000433 result = default_read_string(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000434 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000435 result = default_read_double(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000436 } else if (ttype == TTYPE_STRUCT) {
437 VALUE klass = rb_hash_aref(field_info, class_sym);
438 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000439
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 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000445 } else if (ttype == TTYPE_MAP) {
446 int i;
447
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000448 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000449 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));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000452
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000453 // Check the declared key and value types against the expected ones and skip the map contents
454 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000455 VALUE key_info = rb_hash_aref(field_info, key_sym);
456 VALUE value_info = rb_hash_aref(field_info, value_sym);
457
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000458 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));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000461 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000462 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000463
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000464 for (i = 0; i < num_entries; ++i) {
465 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000466
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000467 key = read_anything(protocol, key_ttype, key_info);
468 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000469
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000470 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000477 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000478
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000479 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000480 } else if (ttype == TTYPE_LIST) {
481 int i;
482
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000483 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000484 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
485 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000486
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000487 // 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000503 }
504
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000505 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000506 } else if (ttype == TTYPE_SET) {
507 VALUE items;
508 int i;
509
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000510 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000511 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
512 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000513
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000514 // 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);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000532 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000533
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000534 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000535 } else {
536 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
537 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000538
Bryan Duxburyc0166282009-02-02 00:48:17 +0000539 return result;
540}
541
542static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000543 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000544 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000545
546 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000547
Bryan Duxburyc0166282009-02-02 00:48:17 +0000548 // read each field
549 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000550 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000551 VALUE field_type_value = rb_ary_entry(field_header, 1);
552 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000553
Bryan Duxburyc0166282009-02-02 00:48:17 +0000554 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 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000573
Bryan Duxburyc0166282009-02-02 00:48:17 +0000574 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000575 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000576 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000577
Bryan Duxburyc0166282009-02-02 00:48:17 +0000578 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000579 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000580
Bryan Duxbury834895d2009-10-15 01:20:34 +0000581 // call validate
582 rb_funcall(self, validate_method_id, 0);
583
Bryan Duxburyc0166282009-02-02 00:48:17 +0000584 return Qnil;
585}
586
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000587
588// --------------------------------
589// Union section
590// --------------------------------
591
592static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
593 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000594 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000595
596 VALUE struct_fields = STRUCT_FIELDS(self);
597
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000598 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000599 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);
Roger Meier02405722014-01-12 23:29:11 +0100610 rb_iv_set(self, "@setfield", rb_str_intern(name));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000611 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
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000620 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000621
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000622 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000623 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
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000630 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000631 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000632
633 // call validate
634 rb_funcall(self, validate_method_id, 0);
635
636 return Qnil;
637}
638
639static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
640 // call validate
641 rb_funcall(self, validate_method_id, 0);
642
643 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000644 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000645
646 VALUE struct_fields = STRUCT_FIELDS(self);
647
648 VALUE setfield = rb_ivar_get(self, setfield_id);
649 VALUE setvalue = rb_ivar_get(self, setvalue_id);
650 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
651
652 VALUE field_info = rb_hash_aref(struct_fields, field_id);
653
654 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
655 int ttype = FIX2INT(ttype_value);
656
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000657 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000658
659 write_anything(ttype, setvalue, protocol, field_info);
660
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000661 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000662
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000663 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000664
665 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000666 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000667
668 return Qnil;
669}
670
Bryan Duxburyc0166282009-02-02 00:48:17 +0000671void Init_struct() {
672 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000673
Bryan Duxburyc0166282009-02-02 00:48:17 +0000674 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
675 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000676
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000677 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
678
679 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
680 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
681
682 setfield_id = rb_intern("@setfield");
683 setvalue_id = rb_intern("@value");
684
685 to_s_method_id = rb_intern("to_s");
686 name_to_id_method_id = rb_intern("name_to_id");
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000687 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Bryan Duxbury65073e52010-02-23 15:46:46 +0000688}