blob: b882344baf029e440735f038bbbee78f82dd8011 [file] [log] [blame]
Bryan Duxburyc0166282009-02-02 00:48:17 +00001#include <struct.h>
2#include <constants.h>
3
Bryan Duxbury1e80d442009-02-03 18:16:54 +00004#ifndef HAVE_STRLCPY
5
6static
7size_t
8strlcpy (char *dst, const char *src, size_t dst_sz)
9{
10 size_t n;
11
12 for (n = 0; n < dst_sz; n++) {
13 if ((*dst++ = *src++) == '\0')
14 break;
15 }
16
17 if (n < dst_sz)
18 return n;
19 if (n > 0)
20 *(dst - 1) = '\0';
21 return n + strlen (src);
22}
23
24#endif
25
Bryan Duxburyc0166282009-02-02 00:48:17 +000026static native_proto_method_table *mt;
27
28#define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
29#define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
30
31//-------------------------------------------
32// Writing section
33//-------------------------------------------
34
35// default fn pointers for protocol stuff here
36
37VALUE default_write_bool(VALUE protocol, VALUE value) {
38 rb_funcall(protocol, write_boolean_method_id, 1, value);
39 return Qnil;
40}
41
42VALUE default_write_byte(VALUE protocol, VALUE value) {
43 rb_funcall(protocol, write_byte_method_id, 1, value);
44 return Qnil;
45}
46
47VALUE default_write_i16(VALUE protocol, VALUE value) {
48 rb_funcall(protocol, write_i16_method_id, 1, value);
49 return Qnil;
50}
51
52VALUE default_write_i32(VALUE protocol, VALUE value) {
53 rb_funcall(protocol, write_i32_method_id, 1, value);
54 return Qnil;
55}
56
57VALUE default_write_i64(VALUE protocol, VALUE value) {
58 rb_funcall(protocol, write_i64_method_id, 1, value);
59 return Qnil;
60}
61
62VALUE default_write_double(VALUE protocol, VALUE value) {
63 rb_funcall(protocol, write_double_method_id, 1, value);
64 return Qnil;
65}
66
67VALUE default_write_string(VALUE protocol, VALUE value) {
68 rb_funcall(protocol, write_string_method_id, 1, value);
69 return Qnil;
70}
71
72VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
73 rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
74 return Qnil;
75}
76
77VALUE default_write_list_end(VALUE protocol) {
78 rb_funcall(protocol, write_list_end_method_id, 0);
79 return Qnil;
80}
81
82VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
83 rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
84 return Qnil;
85}
86
87VALUE default_write_set_end(VALUE protocol) {
88 rb_funcall(protocol, write_set_end_method_id, 0);
89 return Qnil;
90}
91
92VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
93 rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
94 return Qnil;
95}
96
97VALUE default_write_map_end(VALUE protocol) {
98 rb_funcall(protocol, write_map_end_method_id, 0);
99 return Qnil;
100}
101
102VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
103 rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
104 return Qnil;
105}
106
107VALUE default_write_struct_end(VALUE protocol) {
108 rb_funcall(protocol, write_struct_end_method_id, 0);
109 return Qnil;
110}
111
112VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
113 rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
114 return Qnil;
115}
116
117VALUE default_write_field_end(VALUE protocol) {
118 rb_funcall(protocol, write_field_end_method_id, 0);
119 return Qnil;
120}
121
122VALUE default_write_field_stop(VALUE protocol) {
123 rb_funcall(protocol, write_field_stop_method_id, 0);
124 return Qnil;
125}
126
127VALUE default_read_field_begin(VALUE protocol) {
128 return rb_funcall(protocol, read_field_begin_method_id, 0);
129}
130
131VALUE default_read_field_end(VALUE protocol) {
132 return rb_funcall(protocol, read_field_end_method_id, 0);
133}
134
135VALUE default_read_map_begin(VALUE protocol) {
136 return rb_funcall(protocol, read_map_begin_method_id, 0);
137}
138
139VALUE default_read_map_end(VALUE protocol) {
140 return rb_funcall(protocol, read_map_end_method_id, 0);
141}
142
143VALUE default_read_list_begin(VALUE protocol) {
144 return rb_funcall(protocol, read_list_begin_method_id, 0);
145}
146
147VALUE default_read_list_end(VALUE protocol) {
148 return rb_funcall(protocol, read_list_end_method_id, 0);
149}
150
151VALUE default_read_set_begin(VALUE protocol) {
152 return rb_funcall(protocol, read_set_begin_method_id, 0);
153}
154
155VALUE default_read_set_end(VALUE protocol) {
156 return rb_funcall(protocol, read_set_end_method_id, 0);
157}
158
159VALUE default_read_byte(VALUE protocol) {
160 return rb_funcall(protocol, read_byte_method_id, 0);
161}
162
163VALUE default_read_bool(VALUE protocol) {
164 return rb_funcall(protocol, read_bool_method_id, 0);
165}
166
167VALUE default_read_i16(VALUE protocol) {
168 return rb_funcall(protocol, read_i16_method_id, 0);
169}
170
171VALUE default_read_i32(VALUE protocol) {
172 return rb_funcall(protocol, read_i32_method_id, 0);
173}
174
175VALUE default_read_i64(VALUE protocol) {
176 return rb_funcall(protocol, read_i64_method_id, 0);
177}
178
179VALUE default_read_double(VALUE protocol) {
180 return rb_funcall(protocol, read_double_method_id, 0);
181}
182
183VALUE default_read_string(VALUE protocol) {
184 return rb_funcall(protocol, read_string_method_id, 0);
185}
186
187VALUE default_read_struct_begin(VALUE protocol) {
188 return rb_funcall(protocol, read_struct_begin_method_id, 0);
189}
190
191VALUE default_read_struct_end(VALUE protocol) {
192 return rb_funcall(protocol, read_struct_end_method_id, 0);
193}
194
195static void set_default_proto_function_pointers() {
196 mt = ALLOC(native_proto_method_table);
197
198 mt->write_field_begin = default_write_field_begin;
199 mt->write_field_stop = default_write_field_stop;
200 mt->write_map_begin = default_write_map_begin;
201 mt->write_map_end = default_write_map_end;
202 mt->write_list_begin = default_write_list_begin;
203 mt->write_list_end = default_write_list_end;
204 mt->write_set_begin = default_write_set_begin;
205 mt->write_set_end = default_write_set_end;
206 mt->write_byte = default_write_byte;
207 mt->write_bool = default_write_bool;
208 mt->write_i16 = default_write_i16;
209 mt->write_i32 = default_write_i32;
210 mt->write_i64 = default_write_i64;
211 mt->write_double = default_write_double;
212 mt->write_string = default_write_string;
213 mt->write_struct_begin = default_write_struct_begin;
214 mt->write_struct_end = default_write_struct_end;
215 mt->write_field_end = default_write_field_end;
216
217 mt->read_struct_begin = default_read_struct_begin;
218 mt->read_struct_end = default_read_struct_end;
219 mt->read_field_begin = default_read_field_begin;
220 mt->read_field_end = default_read_field_end;
221 mt->read_map_begin = default_read_map_begin;
222 mt->read_map_end = default_read_map_end;
223 mt->read_list_begin = default_read_list_begin;
224 mt->read_list_end = default_read_list_end;
225 mt->read_set_begin = default_read_set_begin;
226 mt->read_set_end = default_read_set_end;
227 mt->read_byte = default_read_byte;
228 mt->read_bool = default_read_bool;
229 mt->read_i16 = default_read_i16;
230 mt->read_i32 = default_read_i32;
231 mt->read_i64 = default_read_i64;
232 mt->read_double = default_read_double;
233 mt->read_string = default_read_string;
234
235}
236
237static void set_native_proto_function_pointers(VALUE protocol) {
238 VALUE method_table_object = rb_const_get(CLASS_OF(protocol), rb_intern("@native_method_table"));
239 // TODO: check nil?
240 Data_Get_Struct(method_table_object, native_proto_method_table, mt);
241}
242
243// end default protocol methods
244
245
246static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
247static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
248
249VALUE get_field_value(VALUE obj, VALUE field_name) {
250 char name_buf[RSTRING(field_name)->len + 1];
251
252 name_buf[0] = '@';
253 strlcpy(&name_buf[1], RSTRING(field_name)->ptr, sizeof(name_buf));
254
255 VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
256
257 return value;
258}
259
260static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
261 int sz, i;
262
263 if (ttype == TTYPE_MAP) {
264 VALUE keys;
265 VALUE key;
266 VALUE val;
267
268 Check_Type(value, T_HASH);
269
270 VALUE key_info = rb_hash_aref(field_info, key_sym);
271 VALUE keytype_value = rb_hash_aref(key_info, type_sym);
272 int keytype = FIX2INT(keytype_value);
273
274 VALUE value_info = rb_hash_aref(field_info, value_sym);
275 VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
276 int valuetype = FIX2INT(valuetype_value);
277
278 keys = rb_funcall(value, keys_method_id, 0);
279
280 sz = RARRAY(keys)->len;
281
282 mt->write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
283
284 for (i = 0; i < sz; i++) {
285 key = rb_ary_entry(keys, i);
286 val = rb_hash_aref(value, key);
287
288 if (IS_CONTAINER(keytype)) {
289 write_container(keytype, key_info, key, protocol);
290 } else {
291 write_anything(keytype, key, protocol, key_info);
292 }
293
294 if (IS_CONTAINER(valuetype)) {
295 write_container(valuetype, value_info, val, protocol);
296 } else {
297 write_anything(valuetype, val, protocol, value_info);
298 }
299 }
300
301 mt->write_map_end(protocol);
302 } else if (ttype == TTYPE_LIST) {
303 Check_Type(value, T_ARRAY);
304
305 sz = RARRAY(value)->len;
306
307 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
308 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
309 int element_type = FIX2INT(element_type_value);
310
311 mt->write_list_begin(protocol, element_type_value, INT2FIX(sz));
312 for (i = 0; i < sz; ++i) {
313 VALUE val = rb_ary_entry(value, i);
314 if (IS_CONTAINER(element_type)) {
315 write_container(element_type, element_type_info, val, protocol);
316 } else {
317 write_anything(element_type, val, protocol, element_type_info);
318 }
319 }
320 mt->write_list_end(protocol);
321 } else if (ttype == TTYPE_SET) {
322 VALUE items;
323
324 if (TYPE(value) == T_ARRAY) {
325 items = value;
326 } else {
327 if (rb_cSet == CLASS_OF(value)) {
328 items = rb_funcall(value, entries_method_id, 0);
329 } else {
330 Check_Type(value, T_HASH);
331 items = rb_funcall(value, keys_method_id, 0);
332 }
333 }
334
335 sz = RARRAY(items)->len;
336
337 VALUE element_type_info = rb_hash_aref(field_info, element_sym);
338 VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
339 int element_type = FIX2INT(element_type_value);
340
341 mt->write_set_begin(protocol, element_type_value, INT2FIX(sz));
342
343 for (i = 0; i < sz; i++) {
344 VALUE val = rb_ary_entry(items, i);
345 if (IS_CONTAINER(element_type)) {
346 write_container(element_type, element_type_info, val, protocol);
347 } else {
348 write_anything(element_type, val, protocol, element_type_info);
349 }
350 }
351
352 mt->write_set_end(protocol);
353 } else {
354 rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
355 }
356}
357
358static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
359 if (ttype == TTYPE_BOOL) {
360 mt->write_bool(protocol, value);
361 } else if (ttype == TTYPE_BYTE) {
362 mt->write_byte(protocol, value);
363 } else if (ttype == TTYPE_I16) {
364 mt->write_i16(protocol, value);
365 } else if (ttype == TTYPE_I32) {
366 mt->write_i32(protocol, value);
367 } else if (ttype == TTYPE_I64) {
368 mt->write_i64(protocol, value);
369 } else if (ttype == TTYPE_DOUBLE) {
370 mt->write_double(protocol, value);
371 } else if (ttype == TTYPE_STRING) {
372 mt->write_string(protocol, value);
373 } else if (IS_CONTAINER(ttype)) {
374 write_container(ttype, field_info, value, protocol);
375 } else if (ttype == TTYPE_STRUCT) {
376 rb_thrift_struct_write(value, protocol);
377 } else {
378 rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
379 }
380}
381
382static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
383 // call validate
384 rb_funcall(self, validate_method_id, 0);
385
386 if (RTEST(rb_funcall(protocol, native_qmark_method_id, 0))) {
387 set_native_proto_function_pointers(protocol);
388 } else {
389 set_default_proto_function_pointers();
390 }
391
392 // write struct begin
393 mt->write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
394
395 // iterate through all the fields here
396 VALUE struct_fields = STRUCT_FIELDS(self);
397 VALUE struct_field_ids_unordered = rb_funcall(struct_fields, keys_method_id, 0);
398 VALUE struct_field_ids_ordered = rb_funcall(struct_field_ids_unordered, sort_method_id, 0);
399
400 int i = 0;
401 for (i=0; i < RARRAY(struct_field_ids_ordered)->len; i++) {
402 VALUE field_id = rb_ary_entry(struct_field_ids_ordered, i);
403 VALUE field_info = rb_hash_aref(struct_fields, field_id);
404
405 VALUE ttype_value = rb_hash_aref(field_info, type_sym);
406 int ttype = FIX2INT(ttype_value);
407 VALUE field_name = rb_hash_aref(field_info, name_sym);
408 VALUE field_value = get_field_value(self, field_name);
409
410 if (!NIL_P(field_value)) {
411 mt->write_field_begin(protocol, field_name, ttype_value, field_id);
412
413 write_anything(ttype, field_value, protocol, field_info);
414
415 mt->write_field_end(protocol);
416 }
417 }
418
419 mt->write_field_stop(protocol);
420
421 // write struct end
422 mt->write_struct_end(protocol);
423
424 return Qnil;
425}
426
427//-------------------------------------------
428// Reading section
429//-------------------------------------------
430
431static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
432
433static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
434 char name_buf[RSTRING(field_name)->len + 1];
435
436 name_buf[0] = '@';
437 strlcpy(&name_buf[1], RSTRING(field_name)->ptr, sizeof(name_buf));
438
439 rb_ivar_set(obj, rb_intern(name_buf), value);
440}
441
442static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
443 VALUE result = Qnil;
444
445 if (ttype == TTYPE_BOOL) {
446 result = mt->read_bool(protocol);
447 } else if (ttype == TTYPE_BYTE) {
448 result = mt->read_byte(protocol);
449 } else if (ttype == TTYPE_I16) {
450 result = mt->read_i16(protocol);
451 } else if (ttype == TTYPE_I32) {
452 result = mt->read_i32(protocol);
453 } else if (ttype == TTYPE_I64) {
454 result = mt->read_i64(protocol);
455 } else if (ttype == TTYPE_STRING) {
456 result = mt->read_string(protocol);
457 } else if (ttype == TTYPE_DOUBLE) {
458 result = mt->read_double(protocol);
459 } else if (ttype == TTYPE_STRUCT) {
460 VALUE klass = rb_hash_aref(field_info, class_sym);
461 result = rb_class_new_instance(0, NULL, klass);
462 rb_thrift_struct_read(result, protocol);
463 } else if (ttype == TTYPE_MAP) {
464 int i;
465
466 VALUE map_header = mt->read_map_begin(protocol);
467 int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
468 int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
469 int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
470
471 VALUE key_info = rb_hash_aref(field_info, key_sym);
472 VALUE value_info = rb_hash_aref(field_info, value_sym);
473
474 result = rb_hash_new();
475
476 for (i = 0; i < num_entries; ++i) {
477 VALUE key, val;
478
479 key = read_anything(protocol, key_ttype, key_info);
480 val = read_anything(protocol, value_ttype, value_info);
481
482 rb_hash_aset(result, key, val);
483 }
484
485 mt->read_map_end(protocol);
486 } else if (ttype == TTYPE_LIST) {
487 int i;
488
489 VALUE list_header = mt->read_list_begin(protocol);
490 int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
491 int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
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
498
499 mt->read_list_end(protocol);
500 } else if (ttype == TTYPE_SET) {
501 VALUE items;
502 int i;
503
504 VALUE set_header = mt->read_set_begin(protocol);
505 int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
506 int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
507 items = rb_ary_new2(num_elements);
508
509 for (i = 0; i < num_elements; ++i) {
510 rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
511 }
512
513
514 mt->read_set_end(protocol);
515
516 result = rb_class_new_instance(1, &items, rb_cSet);
517 } else {
518 rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
519 }
520
521 return result;
522}
523
524static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
525 // read struct begin
526 mt->read_struct_begin(protocol);
527
528 VALUE struct_fields = STRUCT_FIELDS(self);
529
530 // read each field
531 while (true) {
532 VALUE field_header = rb_funcall(protocol, read_field_begin_method_id, 0);
533 VALUE field_type_value = rb_ary_entry(field_header, 1);
534 int field_type = FIX2INT(field_type_value);
535
536 if (field_type == TTYPE_STOP) {
537 break;
538 }
539
540 // make sure we got a type we expected
541 VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
542
543 if (!NIL_P(field_info)) {
544 int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
545 if (field_type == specified_type) {
546 // read the value
547 VALUE name = rb_hash_aref(field_info, name_sym);
548 set_field_value(self, name, read_anything(protocol, field_type, field_info));
549 } else {
550 rb_funcall(protocol, skip_method_id, 1, field_type_value);
551 }
552 } else {
553 rb_funcall(protocol, skip_method_id, 1, field_type_value);
554 }
555
556 // read field end
557 mt->read_field_end(protocol);
558 }
559
560 // read struct end
561 mt->read_struct_end(protocol);
562
563 return Qnil;
564}
565
566void Init_struct() {
567 VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
568
569 rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
570 rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
571
572 set_default_proto_function_pointers();
573}
574