blob: d719e339ab2c41af2ebb154a93d140d426ad5413 [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"
Bryan Duxburyc0166282009-02-02 00:48:17 +000023
Bryan Duxbury33e190c2010-02-16 21:19:01 +000024VALUE thrift_union_class;
25
26ID setfield_id;
27ID setvalue_id;
28
29ID to_s_method_id;
30ID name_to_id_method_id;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +000031static ID sorted_field_ids_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000032
33#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
34#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
35
36//-------------------------------------------
37// Writing section
38//-------------------------------------------
39
40// default fn pointers for protocol stuff here
41
42VALUE default_write_bool(VALUE protocol, VALUE value) {
43 rb_funcall(protocol, write_boolean_method_id, 1, value);
44 return Qnil;
45}
46
47VALUE default_write_byte(VALUE protocol, VALUE value) {
48 rb_funcall(protocol, write_byte_method_id, 1, value);
49 return Qnil;
50}
51
52VALUE default_write_i16(VALUE protocol, VALUE value) {
53 rb_funcall(protocol, write_i16_method_id, 1, value);
54 return Qnil;
55}
56
57VALUE default_write_i32(VALUE protocol, VALUE value) {
58 rb_funcall(protocol, write_i32_method_id, 1, value);
59 return Qnil;
60}
61
62VALUE default_write_i64(VALUE protocol, VALUE value) {
63 rb_funcall(protocol, write_i64_method_id, 1, value);
64 return Qnil;
65}
66
67VALUE default_write_double(VALUE protocol, VALUE value) {
68 rb_funcall(protocol, write_double_method_id, 1, value);
69 return Qnil;
70}
71
72VALUE default_write_string(VALUE protocol, VALUE value) {
73 rb_funcall(protocol, write_string_method_id, 1, value);
74 return Qnil;
75}
76
77VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
78 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
79 return Qnil;
80}
81
82VALUE default_write_list_end(VALUE protocol) {
83 rb_funcall(protocol, write_list_end_method_id, 0);
84 return Qnil;
85}
86
87VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
88 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
89 return Qnil;
90}
91
92VALUE default_write_set_end(VALUE protocol) {
93 rb_funcall(protocol, write_set_end_method_id, 0);
94 return Qnil;
95}
96
97VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
98 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
99 return Qnil;
100}
101
102VALUE default_write_map_end(VALUE protocol) {
103 rb_funcall(protocol, write_map_end_method_id, 0);
104 return Qnil;
105}
106
107VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
108 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
109 return Qnil;
110}
111
112VALUE default_write_struct_end(VALUE protocol) {
113 rb_funcall(protocol, write_struct_end_method_id, 0);
114 return Qnil;
115}
116
117VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
118 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
119 return Qnil;
120}
121
122VALUE default_write_field_end(VALUE protocol) {
123 rb_funcall(protocol, write_field_end_method_id, 0);
124 return Qnil;
125}
126
127VALUE default_write_field_stop(VALUE protocol) {
128 rb_funcall(protocol, write_field_stop_method_id, 0);
129 return Qnil;
130}
131
132VALUE default_read_field_begin(VALUE protocol) {
133 return rb_funcall(protocol, read_field_begin_method_id, 0);
134}
135
136VALUE default_read_field_end(VALUE protocol) {
137 return rb_funcall(protocol, read_field_end_method_id, 0);
138}
139
140VALUE default_read_map_begin(VALUE protocol) {
141 return rb_funcall(protocol, read_map_begin_method_id, 0);
142}
143
144VALUE default_read_map_end(VALUE protocol) {
145 return rb_funcall(protocol, read_map_end_method_id, 0);
146}
147
148VALUE default_read_list_begin(VALUE protocol) {
149 return rb_funcall(protocol, read_list_begin_method_id, 0);
150}
151
152VALUE default_read_list_end(VALUE protocol) {
153 return rb_funcall(protocol, read_list_end_method_id, 0);
154}
155
156VALUE default_read_set_begin(VALUE protocol) {
157 return rb_funcall(protocol, read_set_begin_method_id, 0);
158}
159
160VALUE default_read_set_end(VALUE protocol) {
161 return rb_funcall(protocol, read_set_end_method_id, 0);
162}
163
164VALUE default_read_byte(VALUE protocol) {
165 return rb_funcall(protocol, read_byte_method_id, 0);
166}
167
168VALUE default_read_bool(VALUE protocol) {
169 return rb_funcall(protocol, read_bool_method_id, 0);
170}
171
172VALUE default_read_i16(VALUE protocol) {
173 return rb_funcall(protocol, read_i16_method_id, 0);
174}
175
176VALUE default_read_i32(VALUE protocol) {
177 return rb_funcall(protocol, read_i32_method_id, 0);
178}
179
180VALUE default_read_i64(VALUE protocol) {
181 return rb_funcall(protocol, read_i64_method_id, 0);
182}
183
184VALUE default_read_double(VALUE protocol) {
185 return rb_funcall(protocol, read_double_method_id, 0);
186}
187
188VALUE default_read_string(VALUE protocol) {
189 return rb_funcall(protocol, read_string_method_id, 0);
190}
191
192VALUE default_read_struct_begin(VALUE protocol) {
193 return rb_funcall(protocol, read_struct_begin_method_id, 0);
194}
195
196VALUE default_read_struct_end(VALUE protocol) {
197 return rb_funcall(protocol, read_struct_end_method_id, 0);
198}
199
Bryan Duxburyc0166282009-02-02 00:48:17 +0000200// end default protocol methods
201
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000202static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000203static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
204static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
205
206VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000207 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000208
Bryan Duxburyc0166282009-02-02 00:48:17 +0000209 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000210 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000211
212 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000213
Bryan Duxburyc0166282009-02-02 00:48:17 +0000214 return value;
215}
216
217static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
218 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000219
Bryan Duxburyc0166282009-02-02 00:48:17 +0000220 if (ttype == TTYPE_MAP) {
221 VALUE keys;
222 VALUE key;
223 VALUE val;
224
225 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000226
Bryan Duxburyc0166282009-02-02 00:48:17 +0000227 VALUE key_info = rb_hash_aref(field_info, key_sym);
228 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
229 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000230
Bryan Duxburyc0166282009-02-02 00:48:17 +0000231 VALUE value_info = rb_hash_aref(field_info, value_sym);
232 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
233 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000234
Bryan Duxburyc0166282009-02-02 00:48:17 +0000235 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000236
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000237 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000238
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000239 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000240
Bryan Duxburyc0166282009-02-02 00:48:17 +0000241 for (i = 0; i < sz; i++) {
242 key = rb_ary_entry(keys, i);
243 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000244
Bryan Duxburyc0166282009-02-02 00:48:17 +0000245 if (IS_CONTAINER(keytype)) {
246 write_container(keytype, key_info, key, protocol);
247 } else {
248 write_anything(keytype, key, protocol, key_info);
249 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000250
Bryan Duxburyc0166282009-02-02 00:48:17 +0000251 if (IS_CONTAINER(valuetype)) {
252 write_container(valuetype, value_info, val, protocol);
253 } else {
254 write_anything(valuetype, val, protocol, value_info);
255 }
256 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000257
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000258 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000259 } else if (ttype == TTYPE_LIST) {
260 Check_Type(value, T_ARRAY);
261
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000262 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000263
264 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
265 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
266 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000267
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000268 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000269 for (i = 0; i < sz; ++i) {
270 VALUE val = rb_ary_entry(value, i);
271 if (IS_CONTAINER(element_type)) {
272 write_container(element_type, element_type_info, val, protocol);
273 } else {
274 write_anything(element_type, val, protocol, element_type_info);
275 }
276 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000277 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000278 } else if (ttype == TTYPE_SET) {
279 VALUE items;
280
281 if (TYPE(value) == T_ARRAY) {
282 items = value;
283 } else {
284 if (rb_cSet == CLASS_OF(value)) {
285 items = rb_funcall(value, entries_method_id, 0);
286 } else {
287 Check_Type(value, T_HASH);
288 items = rb_funcall(value, keys_method_id, 0);
289 }
290 }
291
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000292 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000293
294 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
295 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
296 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000297
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000298 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000299
Bryan Duxburyc0166282009-02-02 00:48:17 +0000300 for (i = 0; i < sz; i++) {
301 VALUE val = rb_ary_entry(items, i);
302 if (IS_CONTAINER(element_type)) {
303 write_container(element_type, element_type_info, val, protocol);
304 } else {
305 write_anything(element_type, val, protocol, element_type_info);
306 }
307 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000308
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000309 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000310 } else {
311 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
312 }
313}
314
315static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
316 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000317 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000318 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000319 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000320 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000321 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000322 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000323 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000324 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000325 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000326 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000327 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000328 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000329 default_write_string(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000330 } else if (IS_CONTAINER(ttype)) {
331 write_container(ttype, field_info, value, protocol);
332 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000333 if (rb_obj_is_kind_of(value, thrift_union_class)) {
334 rb_thrift_union_write(value, protocol);
335 } else {
336 rb_thrift_struct_write(value, protocol);
337 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000338 } else {
339 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
340 }
341}
342
343static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
344 // call validate
345 rb_funcall(self, validate_method_id, 0);
346
Bryan Duxburyc0166282009-02-02 00:48:17 +0000347 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000348 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000349
Bryan Duxburyc0166282009-02-02 00:48:17 +0000350 // iterate through all the fields here
351 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000352 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000353
Bryan Duxburyc0166282009-02-02 00:48:17 +0000354 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000355 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
356 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000357
Bryan Duxburyc0166282009-02-02 00:48:17 +0000358 VALUE field_info = rb_hash_aref(struct_fields, field_id);
359
360 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
361 int ttype = FIX2INT(ttype_value);
362 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000363
Bryan Duxburyc0166282009-02-02 00:48:17 +0000364 VALUE field_value = get_field_value(self, field_name);
365
366 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000367 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000368
Bryan Duxburyc0166282009-02-02 00:48:17 +0000369 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000370
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000371 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000372 }
373 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000374
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000375 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000376
Bryan Duxburyc0166282009-02-02 00:48:17 +0000377 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000378 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000379
Bryan Duxburyc0166282009-02-02 00:48:17 +0000380 return Qnil;
381}
382
383//-------------------------------------------
384// Reading section
385//-------------------------------------------
386
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000387static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000388static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000389static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
390static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000391
392static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000393 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000394
395 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000396 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000397
398 rb_ivar_set(obj, rb_intern(name_buf), value);
399}
400
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000401// Helper method to skip the contents of a map (assumes the map header has been read).
402static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
403 int i;
404 for (i = 0; i < size; i++) {
405 rb_funcall(protocol, skip_method_id, 1, key_type_value);
406 rb_funcall(protocol, skip_method_id, 1, value_type_value);
407 }
408}
409
410// Helper method to skip the contents of a list or set (assumes the list/set header has been read).
411static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
412 int i;
413 for (i = 0; i < size; i++) {
414 rb_funcall(protocol, skip_method_id, 1, element_type_value);
415 }
416}
417
Bryan Duxburyc0166282009-02-02 00:48:17 +0000418static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
419 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000420
Bryan Duxburyc0166282009-02-02 00:48:17 +0000421 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000422 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000423 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000424 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000425 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000426 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000427 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000428 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000429 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000430 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000431 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000432 result = default_read_string(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000433 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000434 result = default_read_double(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000435 } else if (ttype == TTYPE_STRUCT) {
436 VALUE klass = rb_hash_aref(field_info, class_sym);
437 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000438
439 if (rb_obj_is_kind_of(result, thrift_union_class)) {
440 rb_thrift_union_read(result, protocol);
441 } else {
442 rb_thrift_struct_read(result, protocol);
443 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000444 } else if (ttype == TTYPE_MAP) {
445 int i;
446
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000447 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000448 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
449 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
450 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000451
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000452 // Check the declared key and value types against the expected ones and skip the map contents
453 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000454 VALUE key_info = rb_hash_aref(field_info, key_sym);
455 VALUE value_info = rb_hash_aref(field_info, value_sym);
456
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000457 if (!NIL_P(key_info) && !NIL_P(value_info)) {
458 int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
459 int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000460 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000461 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000462
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000463 for (i = 0; i < num_entries; ++i) {
464 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000465
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000466 key = read_anything(protocol, key_ttype, key_info);
467 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000468
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000469 rb_hash_aset(result, key, val);
470 }
471 } else {
472 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
473 }
474 } else {
475 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000476 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000477
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000478 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000479 } else if (ttype == TTYPE_LIST) {
480 int i;
481
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000482 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000483 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
484 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000485
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000486 // Check the declared element type against the expected one and skip the list contents
487 // if the types don't match.
488 VALUE element_info = rb_hash_aref(field_info, element_sym);
489 if (!NIL_P(element_info)) {
490 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
491 if (specified_element_type == element_ttype) {
492 result = rb_ary_new2(num_elements);
493
494 for (i = 0; i < num_elements; ++i) {
495 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
496 }
497 } else {
498 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
499 }
500 } else {
501 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000502 }
503
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000504 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000505 } else if (ttype == TTYPE_SET) {
506 VALUE items;
507 int i;
508
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000509 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000510 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
511 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000512
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000513 // Check the declared element type against the expected one and skip the set contents
514 // if the types don't match.
515 VALUE element_info = rb_hash_aref(field_info, element_sym);
516 if (!NIL_P(element_info)) {
517 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
518 if (specified_element_type == element_ttype) {
519 items = rb_ary_new2(num_elements);
520
521 for (i = 0; i < num_elements; ++i) {
522 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
523 }
524
525 result = rb_class_new_instance(1, &items, rb_cSet);
526 } else {
527 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
528 }
529 } else {
530 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000531 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000532
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000533 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000534 } else {
535 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
536 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000537
Bryan Duxburyc0166282009-02-02 00:48:17 +0000538 return result;
539}
540
541static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000542 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000543 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000544
545 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000546
Bryan Duxburyc0166282009-02-02 00:48:17 +0000547 // read each field
548 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000549 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000550 VALUE field_type_value = rb_ary_entry(field_header, 1);
551 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000552
Bryan Duxburyc0166282009-02-02 00:48:17 +0000553 if (field_type == TTYPE_STOP) {
554 break;
555 }
556
557 // make sure we got a type we expected
558 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
559
560 if (!NIL_P(field_info)) {
561 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
562 if (field_type == specified_type) {
563 // read the value
564 VALUE name = rb_hash_aref(field_info, name_sym);
565 set_field_value(self, name, read_anything(protocol, field_type, field_info));
566 } else {
567 rb_funcall(protocol, skip_method_id, 1, field_type_value);
568 }
569 } else {
570 rb_funcall(protocol, skip_method_id, 1, field_type_value);
571 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000572
Bryan Duxburyc0166282009-02-02 00:48:17 +0000573 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000574 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000575 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000576
Bryan Duxburyc0166282009-02-02 00:48:17 +0000577 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000578 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000579
Bryan Duxbury834895d2009-10-15 01:20:34 +0000580 // call validate
581 rb_funcall(self, validate_method_id, 0);
582
Bryan Duxburyc0166282009-02-02 00:48:17 +0000583 return Qnil;
584}
585
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000586
587// --------------------------------
588// Union section
589// --------------------------------
590
591static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
592 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000593 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000594
595 VALUE struct_fields = STRUCT_FIELDS(self);
596
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000597 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000598 VALUE field_type_value = rb_ary_entry(field_header, 1);
599 int field_type = FIX2INT(field_type_value);
600
601 // make sure we got a type we expected
602 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
603
604 if (!NIL_P(field_info)) {
605 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
606 if (field_type == specified_type) {
607 // read the value
608 VALUE name = rb_hash_aref(field_info, name_sym);
609 rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
610 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
611 } else {
612 rb_funcall(protocol, skip_method_id, 1, field_type_value);
613 }
614 } else {
615 rb_funcall(protocol, skip_method_id, 1, field_type_value);
616 }
617
618 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000619 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000620
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000621 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000622 field_type_value = rb_ary_entry(field_header, 1);
623 field_type = FIX2INT(field_type_value);
624
625 if (field_type != TTYPE_STOP) {
626 rb_raise(rb_eRuntimeError, "too many fields in union!");
627 }
628
629 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000630 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000631
632 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000633 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000634
635 // call validate
636 rb_funcall(self, validate_method_id, 0);
637
638 return Qnil;
639}
640
641static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
642 // call validate
643 rb_funcall(self, validate_method_id, 0);
644
645 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000646 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000647
648 VALUE struct_fields = STRUCT_FIELDS(self);
649
650 VALUE setfield = rb_ivar_get(self, setfield_id);
651 VALUE setvalue = rb_ivar_get(self, setvalue_id);
652 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
653
654 VALUE field_info = rb_hash_aref(struct_fields, field_id);
655
656 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
657 int ttype = FIX2INT(ttype_value);
658
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000659 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000660
661 write_anything(ttype, setvalue, protocol, field_info);
662
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000663 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000664
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000665 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000666
667 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000668 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000669
670 return Qnil;
671}
672
Bryan Duxburyc0166282009-02-02 00:48:17 +0000673void Init_struct() {
674 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000675
Bryan Duxburyc0166282009-02-02 00:48:17 +0000676 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
677 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000678
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000679 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
680
681 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
682 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
683
684 setfield_id = rb_intern("@setfield");
685 setvalue_id = rb_intern("@value");
686
687 to_s_method_id = rb_intern("to_s");
688 name_to_id_method_id = rb_intern("name_to_id");
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000689 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Bryan Duxbury65073e52010-02-23 15:46:46 +0000690}