blob: 8234573035f03fb6aa8cdc0a043558660c115141 [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 Duxbury1e80d442009-02-03 18:16:54 +000024#ifndef HAVE_STRLCPY
25
26static
27size_t
28strlcpy (char *dst, const char *src, size_t dst_sz)
29{
30 size_t n;
31
32 for (n = 0; n < dst_sz; n++) {
33 if ((*dst++ = *src++) == '\0')
34 break;
35 }
36
37 if (n < dst_sz)
38 return n;
39 if (n > 0)
40 *(dst - 1) = '\0';
41 return n + strlen (src);
42}
Bryan Duxbury09d13c22010-08-11 18:37:25 +000043#else
44/*
45 Ruby 1.9.x includes the OpenBSD implementation of strlcpy.
46 See missing/strlcpy.c in Ruby 1.9 source
47 */
48extern size_t strlcpy(char *, const char *, size_t);
Bryan Duxbury1e80d442009-02-03 18:16:54 +000049#endif
50
Bryan Duxbury33e190c2010-02-16 21:19:01 +000051VALUE thrift_union_class;
52
53ID setfield_id;
54ID setvalue_id;
55
56ID to_s_method_id;
57ID name_to_id_method_id;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +000058static ID sorted_field_ids_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000059
60#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
61#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
62
63//-------------------------------------------
64// Writing section
65//-------------------------------------------
66
67// default fn pointers for protocol stuff here
68
69VALUE default_write_bool(VALUE protocol, VALUE value) {
70 rb_funcall(protocol, write_boolean_method_id, 1, value);
71 return Qnil;
72}
73
74VALUE default_write_byte(VALUE protocol, VALUE value) {
75 rb_funcall(protocol, write_byte_method_id, 1, value);
76 return Qnil;
77}
78
79VALUE default_write_i16(VALUE protocol, VALUE value) {
80 rb_funcall(protocol, write_i16_method_id, 1, value);
81 return Qnil;
82}
83
84VALUE default_write_i32(VALUE protocol, VALUE value) {
85 rb_funcall(protocol, write_i32_method_id, 1, value);
86 return Qnil;
87}
88
89VALUE default_write_i64(VALUE protocol, VALUE value) {
90 rb_funcall(protocol, write_i64_method_id, 1, value);
91 return Qnil;
92}
93
94VALUE default_write_double(VALUE protocol, VALUE value) {
95 rb_funcall(protocol, write_double_method_id, 1, value);
96 return Qnil;
97}
98
99VALUE default_write_string(VALUE protocol, VALUE value) {
100 rb_funcall(protocol, write_string_method_id, 1, value);
101 return Qnil;
102}
103
104VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
105 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
106 return Qnil;
107}
108
109VALUE default_write_list_end(VALUE protocol) {
110 rb_funcall(protocol, write_list_end_method_id, 0);
111 return Qnil;
112}
113
114VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
115 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
116 return Qnil;
117}
118
119VALUE default_write_set_end(VALUE protocol) {
120 rb_funcall(protocol, write_set_end_method_id, 0);
121 return Qnil;
122}
123
124VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
125 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
126 return Qnil;
127}
128
129VALUE default_write_map_end(VALUE protocol) {
130 rb_funcall(protocol, write_map_end_method_id, 0);
131 return Qnil;
132}
133
134VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
135 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
136 return Qnil;
137}
138
139VALUE default_write_struct_end(VALUE protocol) {
140 rb_funcall(protocol, write_struct_end_method_id, 0);
141 return Qnil;
142}
143
144VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
145 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
146 return Qnil;
147}
148
149VALUE default_write_field_end(VALUE protocol) {
150 rb_funcall(protocol, write_field_end_method_id, 0);
151 return Qnil;
152}
153
154VALUE default_write_field_stop(VALUE protocol) {
155 rb_funcall(protocol, write_field_stop_method_id, 0);
156 return Qnil;
157}
158
159VALUE default_read_field_begin(VALUE protocol) {
160 return rb_funcall(protocol, read_field_begin_method_id, 0);
161}
162
163VALUE default_read_field_end(VALUE protocol) {
164 return rb_funcall(protocol, read_field_end_method_id, 0);
165}
166
167VALUE default_read_map_begin(VALUE protocol) {
168 return rb_funcall(protocol, read_map_begin_method_id, 0);
169}
170
171VALUE default_read_map_end(VALUE protocol) {
172 return rb_funcall(protocol, read_map_end_method_id, 0);
173}
174
175VALUE default_read_list_begin(VALUE protocol) {
176 return rb_funcall(protocol, read_list_begin_method_id, 0);
177}
178
179VALUE default_read_list_end(VALUE protocol) {
180 return rb_funcall(protocol, read_list_end_method_id, 0);
181}
182
183VALUE default_read_set_begin(VALUE protocol) {
184 return rb_funcall(protocol, read_set_begin_method_id, 0);
185}
186
187VALUE default_read_set_end(VALUE protocol) {
188 return rb_funcall(protocol, read_set_end_method_id, 0);
189}
190
191VALUE default_read_byte(VALUE protocol) {
192 return rb_funcall(protocol, read_byte_method_id, 0);
193}
194
195VALUE default_read_bool(VALUE protocol) {
196 return rb_funcall(protocol, read_bool_method_id, 0);
197}
198
199VALUE default_read_i16(VALUE protocol) {
200 return rb_funcall(protocol, read_i16_method_id, 0);
201}
202
203VALUE default_read_i32(VALUE protocol) {
204 return rb_funcall(protocol, read_i32_method_id, 0);
205}
206
207VALUE default_read_i64(VALUE protocol) {
208 return rb_funcall(protocol, read_i64_method_id, 0);
209}
210
211VALUE default_read_double(VALUE protocol) {
212 return rb_funcall(protocol, read_double_method_id, 0);
213}
214
215VALUE default_read_string(VALUE protocol) {
216 return rb_funcall(protocol, read_string_method_id, 0);
217}
218
219VALUE default_read_struct_begin(VALUE protocol) {
220 return rb_funcall(protocol, read_struct_begin_method_id, 0);
221}
222
223VALUE default_read_struct_end(VALUE protocol) {
224 return rb_funcall(protocol, read_struct_end_method_id, 0);
225}
226
Bryan Duxburyc0166282009-02-02 00:48:17 +0000227// end default protocol methods
228
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000229static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000230static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
231static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
232
233VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000234 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000235
Bryan Duxburyc0166282009-02-02 00:48:17 +0000236 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000237 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000238
239 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000240
Bryan Duxburyc0166282009-02-02 00:48:17 +0000241 return value;
242}
243
244static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
245 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000246
Bryan Duxburyc0166282009-02-02 00:48:17 +0000247 if (ttype == TTYPE_MAP) {
248 VALUE keys;
249 VALUE key;
250 VALUE val;
251
252 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000253
Bryan Duxburyc0166282009-02-02 00:48:17 +0000254 VALUE key_info = rb_hash_aref(field_info, key_sym);
255 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
256 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000257
Bryan Duxburyc0166282009-02-02 00:48:17 +0000258 VALUE value_info = rb_hash_aref(field_info, value_sym);
259 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
260 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000261
Bryan Duxburyc0166282009-02-02 00:48:17 +0000262 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000263
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000264 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000265
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000266 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000267
Bryan Duxburyc0166282009-02-02 00:48:17 +0000268 for (i = 0; i < sz; i++) {
269 key = rb_ary_entry(keys, i);
270 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000271
Bryan Duxburyc0166282009-02-02 00:48:17 +0000272 if (IS_CONTAINER(keytype)) {
273 write_container(keytype, key_info, key, protocol);
274 } else {
275 write_anything(keytype, key, protocol, key_info);
276 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000277
Bryan Duxburyc0166282009-02-02 00:48:17 +0000278 if (IS_CONTAINER(valuetype)) {
279 write_container(valuetype, value_info, val, protocol);
280 } else {
281 write_anything(valuetype, val, protocol, value_info);
282 }
283 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000284
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000285 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000286 } else if (ttype == TTYPE_LIST) {
287 Check_Type(value, T_ARRAY);
288
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000289 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000290
291 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
292 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
293 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000294
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000295 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000296 for (i = 0; i < sz; ++i) {
297 VALUE val = rb_ary_entry(value, i);
298 if (IS_CONTAINER(element_type)) {
299 write_container(element_type, element_type_info, val, protocol);
300 } else {
301 write_anything(element_type, val, protocol, element_type_info);
302 }
303 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000304 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000305 } else if (ttype == TTYPE_SET) {
306 VALUE items;
307
308 if (TYPE(value) == T_ARRAY) {
309 items = value;
310 } else {
311 if (rb_cSet == CLASS_OF(value)) {
312 items = rb_funcall(value, entries_method_id, 0);
313 } else {
314 Check_Type(value, T_HASH);
315 items = rb_funcall(value, keys_method_id, 0);
316 }
317 }
318
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000319 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000320
321 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
322 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
323 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000324
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000325 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000326
Bryan Duxburyc0166282009-02-02 00:48:17 +0000327 for (i = 0; i < sz; i++) {
328 VALUE val = rb_ary_entry(items, i);
329 if (IS_CONTAINER(element_type)) {
330 write_container(element_type, element_type_info, val, protocol);
331 } else {
332 write_anything(element_type, val, protocol, element_type_info);
333 }
334 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000335
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000336 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000337 } else {
338 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
339 }
340}
341
342static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
343 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000344 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000345 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000346 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000347 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000348 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000349 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000350 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000351 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000352 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000353 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000354 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000355 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000356 default_write_string(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000357 } else if (IS_CONTAINER(ttype)) {
358 write_container(ttype, field_info, value, protocol);
359 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000360 if (rb_obj_is_kind_of(value, thrift_union_class)) {
361 rb_thrift_union_write(value, protocol);
362 } else {
363 rb_thrift_struct_write(value, protocol);
364 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000365 } else {
366 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
367 }
368}
369
370static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
371 // call validate
372 rb_funcall(self, validate_method_id, 0);
373
Bryan Duxburyc0166282009-02-02 00:48:17 +0000374 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000375 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000376
Bryan Duxburyc0166282009-02-02 00:48:17 +0000377 // iterate through all the fields here
378 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000379 VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000380
Bryan Duxburyc0166282009-02-02 00:48:17 +0000381 int i = 0;
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000382 for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
383 VALUE field_id = rb_ary_entry(sorted_field_ids, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000384
Bryan Duxburyc0166282009-02-02 00:48:17 +0000385 VALUE field_info = rb_hash_aref(struct_fields, field_id);
386
387 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
388 int ttype = FIX2INT(ttype_value);
389 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000390
Bryan Duxburyc0166282009-02-02 00:48:17 +0000391 VALUE field_value = get_field_value(self, field_name);
392
393 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000394 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000395
Bryan Duxburyc0166282009-02-02 00:48:17 +0000396 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000397
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000398 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000399 }
400 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000401
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000402 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000403
Bryan Duxburyc0166282009-02-02 00:48:17 +0000404 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000405 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000406
Bryan Duxburyc0166282009-02-02 00:48:17 +0000407 return Qnil;
408}
409
410//-------------------------------------------
411// Reading section
412//-------------------------------------------
413
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000414static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000415static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000416static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
417static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000418
419static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000420 char name_buf[RSTRING_LEN(field_name) + 2];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000421
422 name_buf[0] = '@';
Bryan Duxburybcbf6d62011-10-24 17:29:16 +0000423 strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000424
425 rb_ivar_set(obj, rb_intern(name_buf), value);
426}
427
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000428// Helper method to skip the contents of a map (assumes the map header has been read).
429static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
430 int i;
431 for (i = 0; i < size; i++) {
432 rb_funcall(protocol, skip_method_id, 1, key_type_value);
433 rb_funcall(protocol, skip_method_id, 1, value_type_value);
434 }
435}
436
437// Helper method to skip the contents of a list or set (assumes the list/set header has been read).
438static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
439 int i;
440 for (i = 0; i < size; i++) {
441 rb_funcall(protocol, skip_method_id, 1, element_type_value);
442 }
443}
444
Bryan Duxburyc0166282009-02-02 00:48:17 +0000445static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
446 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000447
Bryan Duxburyc0166282009-02-02 00:48:17 +0000448 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000449 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000450 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000451 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000452 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000453 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000454 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000455 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000456 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000457 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000458 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000459 result = default_read_string(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000460 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000461 result = default_read_double(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000462 } else if (ttype == TTYPE_STRUCT) {
463 VALUE klass = rb_hash_aref(field_info, class_sym);
464 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000465
466 if (rb_obj_is_kind_of(result, thrift_union_class)) {
467 rb_thrift_union_read(result, protocol);
468 } else {
469 rb_thrift_struct_read(result, protocol);
470 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000471 } else if (ttype == TTYPE_MAP) {
472 int i;
473
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000474 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000475 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
476 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
477 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000478
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000479 // Check the declared key and value types against the expected ones and skip the map contents
480 // if the types don't match.
Bryan Duxburyc0166282009-02-02 00:48:17 +0000481 VALUE key_info = rb_hash_aref(field_info, key_sym);
482 VALUE value_info = rb_hash_aref(field_info, value_sym);
483
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000484 if (!NIL_P(key_info) && !NIL_P(value_info)) {
485 int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
486 int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
Bryan Duxburye80a1942011-09-20 18:45:56 +0000487 if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000488 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000489
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000490 for (i = 0; i < num_entries; ++i) {
491 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000492
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000493 key = read_anything(protocol, key_ttype, key_info);
494 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000495
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000496 rb_hash_aset(result, key, val);
497 }
498 } else {
499 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
500 }
501 } else {
502 skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000503 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000504
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000505 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000506 } else if (ttype == TTYPE_LIST) {
507 int i;
508
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000509 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000510 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
511 int num_elements = FIX2INT(rb_ary_entry(list_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 list 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 result = rb_ary_new2(num_elements);
520
521 for (i = 0; i < num_elements; ++i) {
522 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
523 }
524 } else {
525 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
526 }
527 } else {
528 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000529 }
530
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000531 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000532 } else if (ttype == TTYPE_SET) {
533 VALUE items;
534 int i;
535
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000536 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000537 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
538 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000539
Bryan Duxbury911d2f12011-05-31 20:03:29 +0000540 // Check the declared element type against the expected one and skip the set contents
541 // if the types don't match.
542 VALUE element_info = rb_hash_aref(field_info, element_sym);
543 if (!NIL_P(element_info)) {
544 int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
545 if (specified_element_type == element_ttype) {
546 items = rb_ary_new2(num_elements);
547
548 for (i = 0; i < num_elements; ++i) {
549 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
550 }
551
552 result = rb_class_new_instance(1, &items, rb_cSet);
553 } else {
554 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
555 }
556 } else {
557 skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000558 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000559
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000560 default_read_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000561 } else {
562 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
563 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000564
Bryan Duxburyc0166282009-02-02 00:48:17 +0000565 return result;
566}
567
568static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000569 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000570 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000571
572 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000573
Bryan Duxburyc0166282009-02-02 00:48:17 +0000574 // read each field
575 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000576 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000577 VALUE field_type_value = rb_ary_entry(field_header, 1);
578 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000579
Bryan Duxburyc0166282009-02-02 00:48:17 +0000580 if (field_type == TTYPE_STOP) {
581 break;
582 }
583
584 // make sure we got a type we expected
585 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
586
587 if (!NIL_P(field_info)) {
588 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
589 if (field_type == specified_type) {
590 // read the value
591 VALUE name = rb_hash_aref(field_info, name_sym);
592 set_field_value(self, name, read_anything(protocol, field_type, field_info));
593 } else {
594 rb_funcall(protocol, skip_method_id, 1, field_type_value);
595 }
596 } else {
597 rb_funcall(protocol, skip_method_id, 1, field_type_value);
598 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000599
Bryan Duxburyc0166282009-02-02 00:48:17 +0000600 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000601 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000602 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000603
Bryan Duxburyc0166282009-02-02 00:48:17 +0000604 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000605 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000606
Bryan Duxbury834895d2009-10-15 01:20:34 +0000607 // call validate
608 rb_funcall(self, validate_method_id, 0);
609
Bryan Duxburyc0166282009-02-02 00:48:17 +0000610 return Qnil;
611}
612
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000613
614// --------------------------------
615// Union section
616// --------------------------------
617
618static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
619 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000620 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000621
622 VALUE struct_fields = STRUCT_FIELDS(self);
623
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000624 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000625 VALUE field_type_value = rb_ary_entry(field_header, 1);
626 int field_type = FIX2INT(field_type_value);
627
628 // make sure we got a type we expected
629 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
630
631 if (!NIL_P(field_info)) {
632 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
633 if (field_type == specified_type) {
634 // read the value
635 VALUE name = rb_hash_aref(field_info, name_sym);
636 rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
637 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
638 } else {
639 rb_funcall(protocol, skip_method_id, 1, field_type_value);
640 }
641 } else {
642 rb_funcall(protocol, skip_method_id, 1, field_type_value);
643 }
644
645 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000646 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000647
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000648 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000649 field_type_value = rb_ary_entry(field_header, 1);
650 field_type = FIX2INT(field_type_value);
651
652 if (field_type != TTYPE_STOP) {
653 rb_raise(rb_eRuntimeError, "too many fields in union!");
654 }
655
656 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000657 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000658
659 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000660 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000661
662 // call validate
663 rb_funcall(self, validate_method_id, 0);
664
665 return Qnil;
666}
667
668static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
669 // call validate
670 rb_funcall(self, validate_method_id, 0);
671
672 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000673 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000674
675 VALUE struct_fields = STRUCT_FIELDS(self);
676
677 VALUE setfield = rb_ivar_get(self, setfield_id);
678 VALUE setvalue = rb_ivar_get(self, setvalue_id);
679 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
680
681 VALUE field_info = rb_hash_aref(struct_fields, field_id);
682
683 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
684 int ttype = FIX2INT(ttype_value);
685
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000686 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000687
688 write_anything(ttype, setvalue, protocol, field_info);
689
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000690 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000691
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000692 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000693
694 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000695 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000696
697 return Qnil;
698}
699
Bryan Duxburyc0166282009-02-02 00:48:17 +0000700void Init_struct() {
701 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000702
Bryan Duxburyc0166282009-02-02 00:48:17 +0000703 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
704 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000705
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000706 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
707
708 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
709 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
710
711 setfield_id = rb_intern("@setfield");
712 setvalue_id = rb_intern("@value");
713
714 to_s_method_id = rb_intern("to_s");
715 name_to_id_method_id = rb_intern("name_to_id");
Bryan Duxburyd1df20a2011-06-15 20:52:57 +0000716 sorted_field_ids_method_id = rb_intern("sorted_field_ids");
Bryan Duxbury65073e52010-02-23 15:46:46 +0000717}