THRIFT-332. rb: Compact Protocol in Ruby

This patch includes both a pure Ruby and C-extension port of the Compact Protocol described in THRIFT-110. It also fixes a bug in struct.c that was interfering with native protocol method calls, and adds some utility classes to the Java library for serializing/deserializing to a file for the purpose of testing protocols cross-language.

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@756133 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c
index b882344..20b48b9 100644
--- a/lib/rb/ext/struct.c
+++ b/lib/rb/ext/struct.c
@@ -24,10 +24,30 @@
 #endif
 
 static native_proto_method_table *mt;
+static native_proto_method_table *default_mt;
+static VALUE last_proto_class = Qnil;
 
 #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
 #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
 
+static void set_native_proto_function_pointers(VALUE protocol) {
+  VALUE method_table_object = rb_const_get(CLASS_OF(protocol), rb_intern("@native_method_table"));
+  // TODO: check nil?
+  Data_Get_Struct(method_table_object, native_proto_method_table, mt);
+}
+
+static void check_native_proto_method_table(VALUE protocol) {
+  VALUE protoclass = CLASS_OF(protocol);
+  if (protoclass != last_proto_class) {
+    last_proto_class = protoclass;
+    if (rb_funcall(protocol, native_qmark_method_id, 0) == Qtrue) {
+      set_native_proto_function_pointers(protocol);
+    } else {
+      mt = default_mt;
+    }
+  }
+}
+
 //-------------------------------------------
 // Writing section
 //-------------------------------------------
@@ -193,51 +213,44 @@
 }
 
 static void set_default_proto_function_pointers() {
-  mt = ALLOC(native_proto_method_table);
-  
-  mt->write_field_begin = default_write_field_begin;
-  mt->write_field_stop = default_write_field_stop;
-  mt->write_map_begin = default_write_map_begin;
-  mt->write_map_end = default_write_map_end;
-  mt->write_list_begin = default_write_list_begin;
-  mt->write_list_end = default_write_list_end;
-  mt->write_set_begin = default_write_set_begin;
-  mt->write_set_end = default_write_set_end;
-  mt->write_byte = default_write_byte;
-  mt->write_bool = default_write_bool;
-  mt->write_i16 = default_write_i16;
-  mt->write_i32 = default_write_i32;
-  mt->write_i64 = default_write_i64;
-  mt->write_double = default_write_double;
-  mt->write_string = default_write_string;
-  mt->write_struct_begin = default_write_struct_begin;
-  mt->write_struct_end = default_write_struct_end;
-  mt->write_field_end = default_write_field_end;
+  default_mt = ALLOC(native_proto_method_table);
 
-  mt->read_struct_begin = default_read_struct_begin;
-  mt->read_struct_end = default_read_struct_end;
-  mt->read_field_begin = default_read_field_begin;
-  mt->read_field_end = default_read_field_end;
-  mt->read_map_begin = default_read_map_begin;
-  mt->read_map_end = default_read_map_end;
-  mt->read_list_begin = default_read_list_begin;
-  mt->read_list_end = default_read_list_end;
-  mt->read_set_begin = default_read_set_begin;
-  mt->read_set_end = default_read_set_end;
-  mt->read_byte = default_read_byte;
-  mt->read_bool = default_read_bool;
-  mt->read_i16 = default_read_i16;
-  mt->read_i32 = default_read_i32;
-  mt->read_i64 = default_read_i64;
-  mt->read_double = default_read_double;
-  mt->read_string = default_read_string;
-  
-}
+  default_mt->write_field_begin = default_write_field_begin;
+  default_mt->write_field_stop = default_write_field_stop;
+  default_mt->write_map_begin = default_write_map_begin;
+  default_mt->write_map_end = default_write_map_end;
+  default_mt->write_list_begin = default_write_list_begin;
+  default_mt->write_list_end = default_write_list_end;
+  default_mt->write_set_begin = default_write_set_begin;
+  default_mt->write_set_end = default_write_set_end;
+  default_mt->write_byte = default_write_byte;
+  default_mt->write_bool = default_write_bool;
+  default_mt->write_i16 = default_write_i16;
+  default_mt->write_i32 = default_write_i32;
+  default_mt->write_i64 = default_write_i64;
+  default_mt->write_double = default_write_double;
+  default_mt->write_string = default_write_string;
+  default_mt->write_struct_begin = default_write_struct_begin;
+  default_mt->write_struct_end = default_write_struct_end;
+  default_mt->write_field_end = default_write_field_end;
 
-static void set_native_proto_function_pointers(VALUE protocol) {
-  VALUE method_table_object = rb_const_get(CLASS_OF(protocol), rb_intern("@native_method_table"));
-  // TODO: check nil?
-  Data_Get_Struct(method_table_object, native_proto_method_table, mt);
+  default_mt->read_struct_begin = default_read_struct_begin;
+  default_mt->read_struct_end = default_read_struct_end;
+  default_mt->read_field_begin = default_read_field_begin;
+  default_mt->read_field_end = default_read_field_end;
+  default_mt->read_map_begin = default_read_map_begin;
+  default_mt->read_map_end = default_read_map_end;
+  default_mt->read_list_begin = default_read_list_begin;
+  default_mt->read_list_end = default_read_list_end;
+  default_mt->read_set_begin = default_read_set_begin;
+  default_mt->read_set_end = default_read_set_end;
+  default_mt->read_byte = default_read_byte;
+  default_mt->read_bool = default_read_bool;
+  default_mt->read_i16 = default_read_i16;
+  default_mt->read_i32 = default_read_i32;
+  default_mt->read_i64 = default_read_i64;
+  default_mt->read_double = default_read_double;
+  default_mt->read_string = default_read_string;
 }
 
 // end default protocol methods
@@ -383,11 +396,12 @@
   // call validate
   rb_funcall(self, validate_method_id, 0);
 
-  if (RTEST(rb_funcall(protocol, native_qmark_method_id, 0))) {
-    set_native_proto_function_pointers(protocol);
-  } else {
-    set_default_proto_function_pointers();
-  }
+  // if (rb_funcall(protocol, native_qmark_method_id, 0) == Qtrue) {
+  //   set_native_proto_function_pointers(protocol);
+  // } else {
+  //   set_default_proto_function_pointers();
+  // }
+  check_native_proto_method_table(protocol);
   
   // write struct begin
   mt->write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
@@ -522,6 +536,8 @@
 }
 
 static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
+  check_native_proto_method_table(protocol);
+  
   // read struct begin
   mt->read_struct_begin(protocol);