blob: 79b1e01cf198989d82195804f21de88393b83f26 [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 Duxburyc0166282009-02-02 00:48:17 +000046static native_proto_method_table *mt;
Bryan Duxburyd815c212009-03-19 18:57:43 +000047static native_proto_method_table *default_mt;
Bryan Duxbury33e190c2010-02-16 21:19:01 +000048
49VALUE thrift_union_class;
50
51ID setfield_id;
52ID setvalue_id;
53
54ID to_s_method_id;
55ID name_to_id_method_id;
Bryan Duxburyc0166282009-02-02 00:48:17 +000056
57#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
58#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
59
60//-------------------------------------------
61// Writing section
62//-------------------------------------------
63
64// default fn pointers for protocol stuff here
65
66VALUE default_write_bool(VALUE protocol, VALUE value) {
67 rb_funcall(protocol, write_boolean_method_id, 1, value);
68 return Qnil;
69}
70
71VALUE default_write_byte(VALUE protocol, VALUE value) {
72 rb_funcall(protocol, write_byte_method_id, 1, value);
73 return Qnil;
74}
75
76VALUE default_write_i16(VALUE protocol, VALUE value) {
77 rb_funcall(protocol, write_i16_method_id, 1, value);
78 return Qnil;
79}
80
81VALUE default_write_i32(VALUE protocol, VALUE value) {
82 rb_funcall(protocol, write_i32_method_id, 1, value);
83 return Qnil;
84}
85
86VALUE default_write_i64(VALUE protocol, VALUE value) {
87 rb_funcall(protocol, write_i64_method_id, 1, value);
88 return Qnil;
89}
90
91VALUE default_write_double(VALUE protocol, VALUE value) {
92 rb_funcall(protocol, write_double_method_id, 1, value);
93 return Qnil;
94}
95
96VALUE default_write_string(VALUE protocol, VALUE value) {
97 rb_funcall(protocol, write_string_method_id, 1, value);
98 return Qnil;
99}
100
101VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
102 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
103 return Qnil;
104}
105
106VALUE default_write_list_end(VALUE protocol) {
107 rb_funcall(protocol, write_list_end_method_id, 0);
108 return Qnil;
109}
110
111VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
112 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
113 return Qnil;
114}
115
116VALUE default_write_set_end(VALUE protocol) {
117 rb_funcall(protocol, write_set_end_method_id, 0);
118 return Qnil;
119}
120
121VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
122 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
123 return Qnil;
124}
125
126VALUE default_write_map_end(VALUE protocol) {
127 rb_funcall(protocol, write_map_end_method_id, 0);
128 return Qnil;
129}
130
131VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
132 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
133 return Qnil;
134}
135
136VALUE default_write_struct_end(VALUE protocol) {
137 rb_funcall(protocol, write_struct_end_method_id, 0);
138 return Qnil;
139}
140
141VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
142 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
143 return Qnil;
144}
145
146VALUE default_write_field_end(VALUE protocol) {
147 rb_funcall(protocol, write_field_end_method_id, 0);
148 return Qnil;
149}
150
151VALUE default_write_field_stop(VALUE protocol) {
152 rb_funcall(protocol, write_field_stop_method_id, 0);
153 return Qnil;
154}
155
156VALUE default_read_field_begin(VALUE protocol) {
157 return rb_funcall(protocol, read_field_begin_method_id, 0);
158}
159
160VALUE default_read_field_end(VALUE protocol) {
161 return rb_funcall(protocol, read_field_end_method_id, 0);
162}
163
164VALUE default_read_map_begin(VALUE protocol) {
165 return rb_funcall(protocol, read_map_begin_method_id, 0);
166}
167
168VALUE default_read_map_end(VALUE protocol) {
169 return rb_funcall(protocol, read_map_end_method_id, 0);
170}
171
172VALUE default_read_list_begin(VALUE protocol) {
173 return rb_funcall(protocol, read_list_begin_method_id, 0);
174}
175
176VALUE default_read_list_end(VALUE protocol) {
177 return rb_funcall(protocol, read_list_end_method_id, 0);
178}
179
180VALUE default_read_set_begin(VALUE protocol) {
181 return rb_funcall(protocol, read_set_begin_method_id, 0);
182}
183
184VALUE default_read_set_end(VALUE protocol) {
185 return rb_funcall(protocol, read_set_end_method_id, 0);
186}
187
188VALUE default_read_byte(VALUE protocol) {
189 return rb_funcall(protocol, read_byte_method_id, 0);
190}
191
192VALUE default_read_bool(VALUE protocol) {
193 return rb_funcall(protocol, read_bool_method_id, 0);
194}
195
196VALUE default_read_i16(VALUE protocol) {
197 return rb_funcall(protocol, read_i16_method_id, 0);
198}
199
200VALUE default_read_i32(VALUE protocol) {
201 return rb_funcall(protocol, read_i32_method_id, 0);
202}
203
204VALUE default_read_i64(VALUE protocol) {
205 return rb_funcall(protocol, read_i64_method_id, 0);
206}
207
208VALUE default_read_double(VALUE protocol) {
209 return rb_funcall(protocol, read_double_method_id, 0);
210}
211
212VALUE default_read_string(VALUE protocol) {
213 return rb_funcall(protocol, read_string_method_id, 0);
214}
215
216VALUE default_read_struct_begin(VALUE protocol) {
217 return rb_funcall(protocol, read_struct_begin_method_id, 0);
218}
219
220VALUE default_read_struct_end(VALUE protocol) {
221 return rb_funcall(protocol, read_struct_end_method_id, 0);
222}
223
224static void set_default_proto_function_pointers() {
Bryan Duxburyd815c212009-03-19 18:57:43 +0000225 default_mt = ALLOC(native_proto_method_table);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000226
Bryan Duxburyd815c212009-03-19 18:57:43 +0000227 default_mt->write_field_begin = default_write_field_begin;
228 default_mt->write_field_stop = default_write_field_stop;
229 default_mt->write_map_begin = default_write_map_begin;
230 default_mt->write_map_end = default_write_map_end;
231 default_mt->write_list_begin = default_write_list_begin;
232 default_mt->write_list_end = default_write_list_end;
233 default_mt->write_set_begin = default_write_set_begin;
234 default_mt->write_set_end = default_write_set_end;
235 default_mt->write_byte = default_write_byte;
236 default_mt->write_bool = default_write_bool;
237 default_mt->write_i16 = default_write_i16;
238 default_mt->write_i32 = default_write_i32;
239 default_mt->write_i64 = default_write_i64;
240 default_mt->write_double = default_write_double;
241 default_mt->write_string = default_write_string;
242 default_mt->write_struct_begin = default_write_struct_begin;
243 default_mt->write_struct_end = default_write_struct_end;
244 default_mt->write_field_end = default_write_field_end;
Bryan Duxburyc0166282009-02-02 00:48:17 +0000245
Bryan Duxburyd815c212009-03-19 18:57:43 +0000246 default_mt->read_struct_begin = default_read_struct_begin;
247 default_mt->read_struct_end = default_read_struct_end;
248 default_mt->read_field_begin = default_read_field_begin;
249 default_mt->read_field_end = default_read_field_end;
250 default_mt->read_map_begin = default_read_map_begin;
251 default_mt->read_map_end = default_read_map_end;
252 default_mt->read_list_begin = default_read_list_begin;
253 default_mt->read_list_end = default_read_list_end;
254 default_mt->read_set_begin = default_read_set_begin;
255 default_mt->read_set_end = default_read_set_end;
256 default_mt->read_byte = default_read_byte;
257 default_mt->read_bool = default_read_bool;
258 default_mt->read_i16 = default_read_i16;
259 default_mt->read_i32 = default_read_i32;
260 default_mt->read_i64 = default_read_i64;
261 default_mt->read_double = default_read_double;
262 default_mt->read_string = default_read_string;
Bryan Duxburyc0166282009-02-02 00:48:17 +0000263}
264
265// end default protocol methods
266
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000267static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000268static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
269static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
270
271VALUE get_field_value(VALUE obj, VALUE field_name) {
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000272 char name_buf[RSTRING_LEN(field_name) + 1];
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000273
Bryan Duxburyc0166282009-02-02 00:48:17 +0000274 name_buf[0] = '@';
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000275 strlcpy(&name_buf[1], RSTRING_PTR(field_name), sizeof(name_buf));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000276
277 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000278
Bryan Duxburyc0166282009-02-02 00:48:17 +0000279 return value;
280}
281
282static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
283 int sz, i;
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000284
Bryan Duxburyc0166282009-02-02 00:48:17 +0000285 if (ttype == TTYPE_MAP) {
286 VALUE keys;
287 VALUE key;
288 VALUE val;
289
290 Check_Type(value, T_HASH);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000291
Bryan Duxburyc0166282009-02-02 00:48:17 +0000292 VALUE key_info = rb_hash_aref(field_info, key_sym);
293 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
294 int keytype = FIX2INT(keytype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000295
Bryan Duxburyc0166282009-02-02 00:48:17 +0000296 VALUE value_info = rb_hash_aref(field_info, value_sym);
297 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
298 int valuetype = FIX2INT(valuetype_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000299
Bryan Duxburyc0166282009-02-02 00:48:17 +0000300 keys = rb_funcall(value, keys_method_id, 0);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000301
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000302 sz = RARRAY_LEN(keys);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000303
Bryan Duxburyc0166282009-02-02 00:48:17 +0000304 mt->write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000305
Bryan Duxburyc0166282009-02-02 00:48:17 +0000306 for (i = 0; i < sz; i++) {
307 key = rb_ary_entry(keys, i);
308 val = rb_hash_aref(value, key);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000309
Bryan Duxburyc0166282009-02-02 00:48:17 +0000310 if (IS_CONTAINER(keytype)) {
311 write_container(keytype, key_info, key, protocol);
312 } else {
313 write_anything(keytype, key, protocol, key_info);
314 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000315
Bryan Duxburyc0166282009-02-02 00:48:17 +0000316 if (IS_CONTAINER(valuetype)) {
317 write_container(valuetype, value_info, val, protocol);
318 } else {
319 write_anything(valuetype, val, protocol, value_info);
320 }
321 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000322
Bryan Duxburyc0166282009-02-02 00:48:17 +0000323 mt->write_map_end(protocol);
324 } else if (ttype == TTYPE_LIST) {
325 Check_Type(value, T_ARRAY);
326
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000327 sz = RARRAY_LEN(value);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000328
329 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
330 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
331 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000332
Bryan Duxburyc0166282009-02-02 00:48:17 +0000333 mt->write_list_begin(protocol, element_type_value, INT2FIX(sz));
334 for (i = 0; i < sz; ++i) {
335 VALUE val = rb_ary_entry(value, i);
336 if (IS_CONTAINER(element_type)) {
337 write_container(element_type, element_type_info, val, protocol);
338 } else {
339 write_anything(element_type, val, protocol, element_type_info);
340 }
341 }
342 mt->write_list_end(protocol);
343 } else if (ttype == TTYPE_SET) {
344 VALUE items;
345
346 if (TYPE(value) == T_ARRAY) {
347 items = value;
348 } else {
349 if (rb_cSet == CLASS_OF(value)) {
350 items = rb_funcall(value, entries_method_id, 0);
351 } else {
352 Check_Type(value, T_HASH);
353 items = rb_funcall(value, keys_method_id, 0);
354 }
355 }
356
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000357 sz = RARRAY_LEN(items);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000358
359 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
360 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
361 int element_type = FIX2INT(element_type_value);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000362
Bryan Duxburyc0166282009-02-02 00:48:17 +0000363 mt->write_set_begin(protocol, element_type_value, INT2FIX(sz));
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000364
Bryan Duxburyc0166282009-02-02 00:48:17 +0000365 for (i = 0; i < sz; i++) {
366 VALUE val = rb_ary_entry(items, i);
367 if (IS_CONTAINER(element_type)) {
368 write_container(element_type, element_type_info, val, protocol);
369 } else {
370 write_anything(element_type, val, protocol, element_type_info);
371 }
372 }
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000373
Bryan Duxburyc0166282009-02-02 00:48:17 +0000374 mt->write_set_end(protocol);
375 } else {
376 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
377 }
378}
379
380static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
381 if (ttype == TTYPE_BOOL) {
382 mt->write_bool(protocol, value);
383 } else if (ttype == TTYPE_BYTE) {
384 mt->write_byte(protocol, value);
385 } else if (ttype == TTYPE_I16) {
386 mt->write_i16(protocol, value);
387 } else if (ttype == TTYPE_I32) {
388 mt->write_i32(protocol, value);
389 } else if (ttype == TTYPE_I64) {
390 mt->write_i64(protocol, value);
391 } else if (ttype == TTYPE_DOUBLE) {
392 mt->write_double(protocol, value);
393 } else if (ttype == TTYPE_STRING) {
394 mt->write_string(protocol, value);
395 } else if (IS_CONTAINER(ttype)) {
396 write_container(ttype, field_info, value, protocol);
397 } else if (ttype == TTYPE_STRUCT) {
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000398 if (rb_obj_is_kind_of(value, thrift_union_class)) {
399 rb_thrift_union_write(value, protocol);
400 } else {
401 rb_thrift_struct_write(value, protocol);
402 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000403 } else {
404 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
405 }
406}
407
408static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
409 // call validate
410 rb_funcall(self, validate_method_id, 0);
411
Bryan Duxburyccae8842009-07-31 18:47:09 +0000412 // check_native_proto_method_table(protocol);
413
Bryan Duxburyc0166282009-02-02 00:48:17 +0000414 // write struct begin
415 mt->write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000416
Bryan Duxburyc0166282009-02-02 00:48:17 +0000417 // iterate through all the fields here
418 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000419
Bryan Duxburyc0166282009-02-02 00:48:17 +0000420 VALUE struct_field_ids_unordered = rb_funcall(struct_fields, keys_method_id, 0);
421 VALUE struct_field_ids_ordered = rb_funcall(struct_field_ids_unordered, sort_method_id, 0);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000422
Bryan Duxburyc0166282009-02-02 00:48:17 +0000423 int i = 0;
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000424 for (i=0; i < RARRAY_LEN(struct_field_ids_ordered); i++) {
Bryan Duxburyc0166282009-02-02 00:48:17 +0000425 VALUE field_id = rb_ary_entry(struct_field_ids_ordered, i);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000426
Bryan Duxburyc0166282009-02-02 00:48:17 +0000427 VALUE field_info = rb_hash_aref(struct_fields, field_id);
428
429 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
430 int ttype = FIX2INT(ttype_value);
431 VALUE field_name = rb_hash_aref(field_info, name_sym);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000432
Bryan Duxburyc0166282009-02-02 00:48:17 +0000433 VALUE field_value = get_field_value(self, field_name);
434
435 if (!NIL_P(field_value)) {
436 mt->write_field_begin(protocol, field_name, ttype_value, field_id);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000437
Bryan Duxburyc0166282009-02-02 00:48:17 +0000438 write_anything(ttype, field_value, protocol, field_info);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000439
Bryan Duxburyc0166282009-02-02 00:48:17 +0000440 mt->write_field_end(protocol);
441 }
442 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000443
Bryan Duxburyc0166282009-02-02 00:48:17 +0000444 mt->write_field_stop(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000445
Bryan Duxburyc0166282009-02-02 00:48:17 +0000446 // write struct end
447 mt->write_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000448
Bryan Duxburyc0166282009-02-02 00:48:17 +0000449 return Qnil;
450}
451
452//-------------------------------------------
453// Reading section
454//-------------------------------------------
455
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000456static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000457static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
458
459static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000460 char name_buf[RSTRING_LEN(field_name) + 1];
Bryan Duxburyc0166282009-02-02 00:48:17 +0000461
462 name_buf[0] = '@';
Bryan Duxburye3ab50d2009-03-25 21:06:53 +0000463 strlcpy(&name_buf[1], RSTRING_PTR(field_name), sizeof(name_buf));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000464
465 rb_ivar_set(obj, rb_intern(name_buf), value);
466}
467
468static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
469 VALUE result = Qnil;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000470
Bryan Duxburyc0166282009-02-02 00:48:17 +0000471 if (ttype == TTYPE_BOOL) {
472 result = mt->read_bool(protocol);
473 } else if (ttype == TTYPE_BYTE) {
474 result = mt->read_byte(protocol);
475 } else if (ttype == TTYPE_I16) {
476 result = mt->read_i16(protocol);
477 } else if (ttype == TTYPE_I32) {
478 result = mt->read_i32(protocol);
479 } else if (ttype == TTYPE_I64) {
480 result = mt->read_i64(protocol);
481 } else if (ttype == TTYPE_STRING) {
482 result = mt->read_string(protocol);
483 } else if (ttype == TTYPE_DOUBLE) {
484 result = mt->read_double(protocol);
485 } else if (ttype == TTYPE_STRUCT) {
486 VALUE klass = rb_hash_aref(field_info, class_sym);
487 result = rb_class_new_instance(0, NULL, klass);
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000488
489 if (rb_obj_is_kind_of(result, thrift_union_class)) {
490 rb_thrift_union_read(result, protocol);
491 } else {
492 rb_thrift_struct_read(result, protocol);
493 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000494 } else if (ttype == TTYPE_MAP) {
495 int i;
496
497 VALUE map_header = mt->read_map_begin(protocol);
498 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
499 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
500 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000501
Bryan Duxburyc0166282009-02-02 00:48:17 +0000502 VALUE key_info = rb_hash_aref(field_info, key_sym);
503 VALUE value_info = rb_hash_aref(field_info, value_sym);
504
505 result = rb_hash_new();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000506
Bryan Duxburyc0166282009-02-02 00:48:17 +0000507 for (i = 0; i < num_entries; ++i) {
508 VALUE key, val;
Bryan Duxburyccae8842009-07-31 18:47:09 +0000509
Bryan Duxburyc0166282009-02-02 00:48:17 +0000510 key = read_anything(protocol, key_ttype, key_info);
511 val = read_anything(protocol, value_ttype, value_info);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000512
Bryan Duxburyc0166282009-02-02 00:48:17 +0000513 rb_hash_aset(result, key, val);
514 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000515
Bryan Duxburyc0166282009-02-02 00:48:17 +0000516 mt->read_map_end(protocol);
517 } else if (ttype == TTYPE_LIST) {
518 int i;
519
520 VALUE list_header = mt->read_list_begin(protocol);
521 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
522 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
523 result = rb_ary_new2(num_elements);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000524
Bryan Duxburyc0166282009-02-02 00:48:17 +0000525 for (i = 0; i < num_elements; ++i) {
526 rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
527 }
528
Bryan Duxburyc0166282009-02-02 00:48:17 +0000529 mt->read_list_end(protocol);
530 } else if (ttype == TTYPE_SET) {
531 VALUE items;
532 int i;
533
534 VALUE set_header = mt->read_set_begin(protocol);
535 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
536 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
537 items = rb_ary_new2(num_elements);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000538
Bryan Duxburyc0166282009-02-02 00:48:17 +0000539 for (i = 0; i < num_elements; ++i) {
540 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
541 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000542
Bryan Duxburyc0166282009-02-02 00:48:17 +0000543 mt->read_set_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000544
Bryan Duxburyc0166282009-02-02 00:48:17 +0000545 result = rb_class_new_instance(1, &items, rb_cSet);
546 } else {
547 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
548 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000549
Bryan Duxburyc0166282009-02-02 00:48:17 +0000550 return result;
551}
552
553static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
Bryan Duxburyccae8842009-07-31 18:47:09 +0000554 // check_native_proto_method_table(protocol);
555
Bryan Duxburyc0166282009-02-02 00:48:17 +0000556 // read struct begin
557 mt->read_struct_begin(protocol);
558
559 VALUE struct_fields = STRUCT_FIELDS(self);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000560
Bryan Duxburyc0166282009-02-02 00:48:17 +0000561 // read each field
562 while (true) {
Bryan Duxbury5b8b4842009-04-01 20:10:15 +0000563 VALUE field_header = mt->read_field_begin(protocol);
Bryan Duxburyc0166282009-02-02 00:48:17 +0000564 VALUE field_type_value = rb_ary_entry(field_header, 1);
565 int field_type = FIX2INT(field_type_value);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000566
Bryan Duxburyc0166282009-02-02 00:48:17 +0000567 if (field_type == TTYPE_STOP) {
568 break;
569 }
570
571 // make sure we got a type we expected
572 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
573
574 if (!NIL_P(field_info)) {
575 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
576 if (field_type == specified_type) {
577 // read the value
578 VALUE name = rb_hash_aref(field_info, name_sym);
579 set_field_value(self, name, read_anything(protocol, field_type, field_info));
580 } else {
581 rb_funcall(protocol, skip_method_id, 1, field_type_value);
582 }
583 } else {
584 rb_funcall(protocol, skip_method_id, 1, field_type_value);
585 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000586
Bryan Duxburyc0166282009-02-02 00:48:17 +0000587 // read field end
588 mt->read_field_end(protocol);
589 }
Bryan Duxburyccae8842009-07-31 18:47:09 +0000590
Bryan Duxburyc0166282009-02-02 00:48:17 +0000591 // read struct end
592 mt->read_struct_end(protocol);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000593
Bryan Duxbury834895d2009-10-15 01:20:34 +0000594 // call validate
595 rb_funcall(self, validate_method_id, 0);
596
Bryan Duxburyc0166282009-02-02 00:48:17 +0000597 return Qnil;
598}
599
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000600
601// --------------------------------
602// Union section
603// --------------------------------
604
605static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
606 // read struct begin
607 mt->read_struct_begin(protocol);
608
609 VALUE struct_fields = STRUCT_FIELDS(self);
610
611 VALUE field_header = mt->read_field_begin(protocol);
612 VALUE field_type_value = rb_ary_entry(field_header, 1);
613 int field_type = FIX2INT(field_type_value);
614
615 // make sure we got a type we expected
616 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
617
618 if (!NIL_P(field_info)) {
619 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
620 if (field_type == specified_type) {
621 // read the value
622 VALUE name = rb_hash_aref(field_info, name_sym);
623 rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
624 rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
625 } else {
626 rb_funcall(protocol, skip_method_id, 1, field_type_value);
627 }
628 } else {
629 rb_funcall(protocol, skip_method_id, 1, field_type_value);
630 }
631
632 // read field end
633 mt->read_field_end(protocol);
634
635 field_header = mt->read_field_begin(protocol);
636 field_type_value = rb_ary_entry(field_header, 1);
637 field_type = FIX2INT(field_type_value);
638
639 if (field_type != TTYPE_STOP) {
640 rb_raise(rb_eRuntimeError, "too many fields in union!");
641 }
642
643 // read field end
644 mt->read_field_end(protocol);
645
646 // read struct end
647 mt->read_struct_end(protocol);
648
649 // call validate
650 rb_funcall(self, validate_method_id, 0);
651
652 return Qnil;
653}
654
655static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
656 // call validate
657 rb_funcall(self, validate_method_id, 0);
658
659 // write struct begin
660 mt->write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
661
662 VALUE struct_fields = STRUCT_FIELDS(self);
663
664 VALUE setfield = rb_ivar_get(self, setfield_id);
665 VALUE setvalue = rb_ivar_get(self, setvalue_id);
666 VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
667
668 VALUE field_info = rb_hash_aref(struct_fields, field_id);
669
670 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
671 int ttype = FIX2INT(ttype_value);
672
673 mt->write_field_begin(protocol, setfield, ttype_value, field_id);
674
675 write_anything(ttype, setvalue, protocol, field_info);
676
677 mt->write_field_end(protocol);
678
679 mt->write_field_stop(protocol);
680
681 // write struct end
682 mt->write_struct_end(protocol);
683
684 return Qnil;
685}
686
Bryan Duxburyc0166282009-02-02 00:48:17 +0000687void Init_struct() {
688 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
Bryan Duxburyccae8842009-07-31 18:47:09 +0000689
Bryan Duxburyc0166282009-02-02 00:48:17 +0000690 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
691 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
Bryan Duxburyccae8842009-07-31 18:47:09 +0000692
Bryan Duxbury33e190c2010-02-16 21:19:01 +0000693 thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
694
695 rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
696 rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
697
698 setfield_id = rb_intern("@setfield");
699 setvalue_id = rb_intern("@value");
700
701 to_s_method_id = rb_intern("to_s");
702 name_to_id_method_id = rb_intern("name_to_id");
703
Bryan Duxburyc0166282009-02-02 00:48:17 +0000704 set_default_proto_function_pointers();
Bryan Duxburyccae8842009-07-31 18:47:09 +0000705 mt = default_mt;
Bryan Duxbury65073e52010-02-23 15:46:46 +0000706}