blob: c2535916bb7bc215a45aa66166bb1959c8ae0df9 [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 Duxburyc0166282009-02-02 00:48:17 +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}
43
44#endif
45
Bryan Duxbury33e190c2010-02-16 21:19:01 +000046VALUE thrift_union_class;
47
48ID setfield_id;
49ID setvalue_id;
50
51ID to_s_method_id;
52ID name_to_id_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000053
54#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
55#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
56
57//-------------------------------------------
58// Writing section
59//-------------------------------------------
60
61// default fn pointers for protocol stuff here
62
63VALUE default_write_bool(VALUE protocol, VALUE value) {
64 rb_funcall(protocol, write_boolean_method_id, 1, value);
65 return Qnil;
66}
67
68VALUE default_write_byte(VALUE protocol, VALUE value) {
69 rb_funcall(protocol, write_byte_method_id, 1, value);
70 return Qnil;
71}
72
73VALUE default_write_i16(VALUE protocol, VALUE value) {
74 rb_funcall(protocol, write_i16_method_id, 1, value);
75 return Qnil;
76}
77
78VALUE default_write_i32(VALUE protocol, VALUE value) {
79 rb_funcall(protocol, write_i32_method_id, 1, value);
80 return Qnil;
81}
82
83VALUE default_write_i64(VALUE protocol, VALUE value) {
84 rb_funcall(protocol, write_i64_method_id, 1, value);
85 return Qnil;
86}
87
88VALUE default_write_double(VALUE protocol, VALUE value) {
89 rb_funcall(protocol, write_double_method_id, 1, value);
90 return Qnil;
91}
92
93VALUE default_write_string(VALUE protocol, VALUE value) {
94 rb_funcall(protocol, write_string_method_id, 1, value);
95 return Qnil;
96}
97
98VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
99 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
100 return Qnil;
101}
102
103VALUE default_write_list_end(VALUE protocol) {
104 rb_funcall(protocol, write_list_end_method_id, 0);
105 return Qnil;
106}
107
108VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
109 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
110 return Qnil;
111}
112
113VALUE default_write_set_end(VALUE protocol) {
114 rb_funcall(protocol, write_set_end_method_id, 0);
115 return Qnil;
116}
117
118VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
119 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
120 return Qnil;
121}
122
123VALUE default_write_map_end(VALUE protocol) {
124 rb_funcall(protocol, write_map_end_method_id, 0);
125 return Qnil;
126}
127
128VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
129 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
130 return Qnil;
131}
132
133VALUE default_write_struct_end(VALUE protocol) {
134 rb_funcall(protocol, write_struct_end_method_id, 0);
135 return Qnil;
136}
137
138VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
139 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
140 return Qnil;
141}
142
143VALUE default_write_field_end(VALUE protocol) {
144 rb_funcall(protocol, write_field_end_method_id, 0);
145 return Qnil;
146}
147
148VALUE default_write_field_stop(VALUE protocol) {
149 rb_funcall(protocol, write_field_stop_method_id, 0);
150 return Qnil;
151}
152
153VALUE default_read_field_begin(VALUE protocol) {
154 return rb_funcall(protocol, read_field_begin_method_id, 0);
155}
156
157VALUE default_read_field_end(VALUE protocol) {
158 return rb_funcall(protocol, read_field_end_method_id, 0);
159}
160
161VALUE default_read_map_begin(VALUE protocol) {
162 return rb_funcall(protocol, read_map_begin_method_id, 0);
163}
164
165VALUE default_read_map_end(VALUE protocol) {
166 return rb_funcall(protocol, read_map_end_method_id, 0);
167}
168
169VALUE default_read_list_begin(VALUE protocol) {
170 return rb_funcall(protocol, read_list_begin_method_id, 0);
171}
172
173VALUE default_read_list_end(VALUE protocol) {
174 return rb_funcall(protocol, read_list_end_method_id, 0);
175}
176
177VALUE default_read_set_begin(VALUE protocol) {
178 return rb_funcall(protocol, read_set_begin_method_id, 0);
179}
180
181VALUE default_read_set_end(VALUE protocol) {
182 return rb_funcall(protocol, read_set_end_method_id, 0);
183}
184
185VALUE default_read_byte(VALUE protocol) {
186 return rb_funcall(protocol, read_byte_method_id, 0);
187}
188
189VALUE default_read_bool(VALUE protocol) {
190 return rb_funcall(protocol, read_bool_method_id, 0);
191}
192
193VALUE default_read_i16(VALUE protocol) {
194 return rb_funcall(protocol, read_i16_method_id, 0);
195}
196
197VALUE default_read_i32(VALUE protocol) {
198 return rb_funcall(protocol, read_i32_method_id, 0);
199}
200
201VALUE default_read_i64(VALUE protocol) {
202 return rb_funcall(protocol, read_i64_method_id, 0);
203}
204
205VALUE default_read_double(VALUE protocol) {
206 return rb_funcall(protocol, read_double_method_id, 0);
207}
208
209VALUE default_read_string(VALUE protocol) {
210 return rb_funcall(protocol, read_string_method_id, 0);
211}
212
213VALUE default_read_struct_begin(VALUE protocol) {
214 return rb_funcall(protocol, read_struct_begin_method_id, 0);
215}
216
217VALUE default_read_struct_end(VALUE protocol) {
218 return rb_funcall(protocol, read_struct_end_method_id, 0);
219}
220
Bryan Duxburyc0166282009-02-02 00:48:17 +0000221// end default protocol methods
222
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000223static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000224static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
225static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
226
227VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000228 char name_buf[RSTRING_LEN(field_name) + 1];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000229
Bryan Duxburyc0166282009-02-02 00:48:17 +0000230 name_buf[0] = '@';
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000231 strlcpy(&name_buf[1], RSTRING_PTR(field_name), sizeof(name_buf));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000232
233 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000234
Bryan Duxburyc0166282009-02-02 00:48:17 +0000235 return value;
236}
237
238static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
239 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000240
Bryan Duxburyc0166282009-02-02 00:48:17 +0000241 if (ttype == TTYPE_MAP) {
242 VALUE keys;
243 VALUE key;
244 VALUE val;
245
246 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000247
Bryan Duxburyc0166282009-02-02 00:48:17 +0000248 VALUE key_info = rb_hash_aref(field_info, key_sym);
249 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
250 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000251
Bryan Duxburyc0166282009-02-02 00:48:17 +0000252 VALUE value_info = rb_hash_aref(field_info, value_sym);
253 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
254 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000255
Bryan Duxburyc0166282009-02-02 00:48:17 +0000256 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000257
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000258 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000259
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000260 default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000261
Bryan Duxburyc0166282009-02-02 00:48:17 +0000262 for (i = 0; i < sz; i++) {
263 key = rb_ary_entry(keys, i);
264 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000265
Bryan Duxburyc0166282009-02-02 00:48:17 +0000266 if (IS_CONTAINER(keytype)) {
267 write_container(keytype, key_info, key, protocol);
268 } else {
269 write_anything(keytype, key, protocol, key_info);
270 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000271
Bryan Duxburyc0166282009-02-02 00:48:17 +0000272 if (IS_CONTAINER(valuetype)) {
273 write_container(valuetype, value_info, val, protocol);
274 } else {
275 write_anything(valuetype, val, protocol, value_info);
276 }
277 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000278
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000279 default_write_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000280 } else if (ttype == TTYPE_LIST) {
281 Check_Type(value, T_ARRAY);
282
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000283 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000284
285 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
286 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
287 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000288
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000289 default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000290 for (i = 0; i < sz; ++i) {
291 VALUE val = rb_ary_entry(value, i);
292 if (IS_CONTAINER(element_type)) {
293 write_container(element_type, element_type_info, val, protocol);
294 } else {
295 write_anything(element_type, val, protocol, element_type_info);
296 }
297 }
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000298 default_write_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000299 } else if (ttype == TTYPE_SET) {
300 VALUE items;
301
302 if (TYPE(value) == T_ARRAY) {
303 items = value;
304 } else {
305 if (rb_cSet == CLASS_OF(value)) {
306 items = rb_funcall(value, entries_method_id, 0);
307 } else {
308 Check_Type(value, T_HASH);
309 items = rb_funcall(value, keys_method_id, 0);
310 }
311 }
312
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000313 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000314
315 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
316 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
317 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000318
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000319 default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000320
Bryan Duxburyc0166282009-02-02 00:48:17 +0000321 for (i = 0; i < sz; i++) {
322 VALUE val = rb_ary_entry(items, i);
323 if (IS_CONTAINER(element_type)) {
324 write_container(element_type, element_type_info, val, protocol);
325 } else {
326 write_anything(element_type, val, protocol, element_type_info);
327 }
328 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000329
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000330 default_write_set_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000331 } else {
332 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
333 }
334}
335
336static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
337 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000338 default_write_bool(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000339 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000340 default_write_byte(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000341 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000342 default_write_i16(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000343 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000344 default_write_i32(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000345 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000346 default_write_i64(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000347 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000348 default_write_double(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000349 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000350 default_write_string(protocol, value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000351 } else if (IS_CONTAINER(ttype)) {
352 write_container(ttype, field_info, value, protocol);
353 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000354 if (rb_obj_is_kind_of(value, thrift_union_class)) {
355 rb_thrift_union_write(value, protocol);
356 } else {
357 rb_thrift_struct_write(value, protocol);
358 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000359 } else {
360 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
361 }
362}
363
364static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
365 // call validate
366 rb_funcall(self, validate_method_id, 0);
367
Bryan Duxburyc0166282009-02-02 00:48:17 +0000368 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000369 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000370
Bryan Duxburyc0166282009-02-02 00:48:17 +0000371 // iterate through all the fields here
372 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000373
Bryan Duxburyc0166282009-02-02 00:48:17 +0000374 VALUE struct_field_ids_unordered = rb_funcall(struct_fields, keys_method_id, 0);
375 VALUE struct_field_ids_ordered = rb_funcall(struct_field_ids_unordered, sort_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000376
Bryan Duxburyc0166282009-02-02 00:48:17 +0000377 int i = 0;
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000378 for (i=0; i < RARRAY_LEN(struct_field_ids_ordered); i++) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000379 VALUE field_id = rb_ary_entry(struct_field_ids_ordered, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000380
Bryan Duxburyc0166282009-02-02 00:48:17 +0000381 VALUE field_info = rb_hash_aref(struct_fields, field_id);
382
383 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
384 int ttype = FIX2INT(ttype_value);
385 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000386
Bryan Duxburyc0166282009-02-02 00:48:17 +0000387 VALUE field_value = get_field_value(self, field_name);
388
389 if (!NIL_P(field_value)) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000390 default_write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000391
Bryan Duxburyc0166282009-02-02 00:48:17 +0000392 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000393
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000394 default_write_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000395 }
396 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000397
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000398 default_write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000399
Bryan Duxburyc0166282009-02-02 00:48:17 +0000400 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000401 default_write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000402
Bryan Duxburyc0166282009-02-02 00:48:17 +0000403 return Qnil;
404}
405
406//-------------------------------------------
407// Reading section
408//-------------------------------------------
409
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000410static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000411static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
412
413static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000414 char name_buf[RSTRING_LEN(field_name) + 1];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000415
416 name_buf[0] = '@';
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000417 strlcpy(&name_buf[1], RSTRING_PTR(field_name), sizeof(name_buf));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000418
419 rb_ivar_set(obj, rb_intern(name_buf), value);
420}
421
422static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
423 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000424
Bryan Duxburyc0166282009-02-02 00:48:17 +0000425 if (ttype == TTYPE_BOOL) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000426 result = default_read_bool(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000427 } else if (ttype == TTYPE_BYTE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000428 result = default_read_byte(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000429 } else if (ttype == TTYPE_I16) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000430 result = default_read_i16(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000431 } else if (ttype == TTYPE_I32) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000432 result = default_read_i32(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000433 } else if (ttype == TTYPE_I64) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000434 result = default_read_i64(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000435 } else if (ttype == TTYPE_STRING) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000436 result = default_read_string(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000437 } else if (ttype == TTYPE_DOUBLE) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000438 result = default_read_double(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000439 } else if (ttype == TTYPE_STRUCT) {
440 VALUE klass = rb_hash_aref(field_info, class_sym);
441 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000442
443 if (rb_obj_is_kind_of(result, thrift_union_class)) {
444 rb_thrift_union_read(result, protocol);
445 } else {
446 rb_thrift_struct_read(result, protocol);
447 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000448 } else if (ttype == TTYPE_MAP) {
449 int i;
450
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000451 VALUE map_header = default_read_map_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000452 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
453 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
454 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000455
Bryan Duxburyc0166282009-02-02 00:48:17 +0000456 VALUE key_info = rb_hash_aref(field_info, key_sym);
457 VALUE value_info = rb_hash_aref(field_info, value_sym);
458
459 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000460
Bryan Duxburyc0166282009-02-02 00:48:17 +0000461 for (i = 0; i < num_entries; ++i) {
462 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000463
Bryan Duxburyc0166282009-02-02 00:48:17 +0000464 key = read_anything(protocol, key_ttype, key_info);
465 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000466
Bryan Duxburyc0166282009-02-02 00:48:17 +0000467 rb_hash_aset(result, key, val);
468 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000469
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000470 default_read_map_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000471 } else if (ttype == TTYPE_LIST) {
472 int i;
473
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000474 VALUE list_header = default_read_list_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000475 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
476 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
477 result = rb_ary_new2(num_elements);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000478
Bryan Duxburyc0166282009-02-02 00:48:17 +0000479 for (i = 0; i < num_elements; ++i) {
480 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
481 }
482
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000483 default_read_list_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000484 } else if (ttype == TTYPE_SET) {
485 VALUE items;
486 int i;
487
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000488 VALUE set_header = default_read_set_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000489 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
490 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
491 items = rb_ary_new2(num_elements);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000492
Bryan Duxburyc0166282009-02-02 00:48:17 +0000493 for (i = 0; i < num_elements; ++i) {
494 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
495 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000496
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000497 default_read_set_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000498
Bryan Duxburyc0166282009-02-02 00:48:17 +0000499 result = rb_class_new_instance(1, &items, rb_cSet);
500 } else {
501 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
502 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000503
Bryan Duxburyc0166282009-02-02 00:48:17 +0000504 return result;
505}
506
507static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000508 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000509 default_read_struct_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000510
511 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000512
Bryan Duxburyc0166282009-02-02 00:48:17 +0000513 // read each field
514 while (true) {
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000515 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000516 VALUE field_type_value = rb_ary_entry(field_header, 1);
517 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000518
Bryan Duxburyc0166282009-02-02 00:48:17 +0000519 if (field_type == TTYPE_STOP) {
520 break;
521 }
522
523 // make sure we got a type we expected
524 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
525
526 if (!NIL_P(field_info)) {
527 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
528 if (field_type == specified_type) {
529 // read the value
530 VALUE name = rb_hash_aref(field_info, name_sym);
531 set_field_value(self, name, read_anything(protocol, field_type, field_info));
532 } else {
533 rb_funcall(protocol, skip_method_id, 1, field_type_value);
534 }
535 } else {
536 rb_funcall(protocol, skip_method_id, 1, field_type_value);
537 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000538
Bryan Duxburyc0166282009-02-02 00:48:17 +0000539 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000540 default_read_field_end(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000541 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000542
Bryan Duxburyc0166282009-02-02 00:48:17 +0000543 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000544 default_read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000545
Bryan Duxbury834895d2009-10-15 01:20:34 +0000546 // call validate
547 rb_funcall(self, validate_method_id, 0);
548
Bryan Duxburyc0166282009-02-02 00:48:17 +0000549 return Qnil;
550}
551
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000552
553// --------------------------------
554// Union section
555// --------------------------------
556
557static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
558 // read struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000559 default_read_struct_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000560
561 VALUE struct_fields = STRUCT_FIELDS(self);
562
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000563 VALUE field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000564 VALUE field_type_value = rb_ary_entry(field_header, 1);
565 int field_type = FIX2INT(field_type_value);
566
567 // make sure we got a type we expected
568 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
569
570 if (!NIL_P(field_info)) {
571 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
572 if (field_type == specified_type) {
573 // read the value
574 VALUE name = rb_hash_aref(field_info, name_sym);
575 rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
576 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
577 } else {
578 rb_funcall(protocol, skip_method_id, 1, field_type_value);
579 }
580 } else {
581 rb_funcall(protocol, skip_method_id, 1, field_type_value);
582 }
583
584 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000585 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000586
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000587 field_header = default_read_field_begin(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000588 field_type_value = rb_ary_entry(field_header, 1);
589 field_type = FIX2INT(field_type_value);
590
591 if (field_type != TTYPE_STOP) {
592 rb_raise(rb_eRuntimeError, "too many fields in union!");
593 }
594
595 // read field end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000596 default_read_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000597
598 // read struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000599 default_read_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000600
601 // call validate
602 rb_funcall(self, validate_method_id, 0);
603
604 return Qnil;
605}
606
607static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
608 // call validate
609 rb_funcall(self, validate_method_id, 0);
610
611 // write struct begin
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000612 default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000613
614 VALUE struct_fields = STRUCT_FIELDS(self);
615
616 VALUE setfield = rb_ivar_get(self, setfield_id);
617 VALUE setvalue = rb_ivar_get(self, setvalue_id);
618 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
619
620 VALUE field_info = rb_hash_aref(struct_fields, field_id);
621
622 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
623 int ttype = FIX2INT(ttype_value);
624
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000625 default_write_field_begin(protocol, setfield, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000626
627 write_anything(ttype, setvalue, protocol, field_info);
628
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000629 default_write_field_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000630
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000631 default_write_field_stop(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000632
633 // write struct end
Bryan Duxburyd2cc5bb2010-07-28 21:00:06 +0000634 default_write_struct_end(protocol);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000635
636 return Qnil;
637}
638
Bryan Duxburyc0166282009-02-02 00:48:17 +0000639void Init_struct() {
640 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000641
Bryan Duxburyc0166282009-02-02 00:48:17 +0000642 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
643 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000644
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000645 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
646
647 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
648 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
649
650 setfield_id = rb_intern("@setfield");
651 setvalue_id = rb_intern("@value");
652
653 to_s_method_id = rb_intern("to_s");
654 name_to_id_method_id = rb_intern("name_to_id");
Bryan Duxbury65073e52010-02-23 15:46:46 +0000655}