THRIFT-248. ruby: Factor BinaryProtocolAccelerated into separate protocol and struct components

This patch replaces the "binaryprotocolaccelerated" c extension with the "thrift_native" c extension. This new extension creates native implementations for the struct.rb #write and #read methods, Thrift::BinaryProtocol, and Thrift::MemoryBuffer, but keeps ruby-level interfaces, allowing all protocols to benefit from the struct code and the memory buffer. There is however an additional cost associated with going through this ruby layer, but the increased interoperability seems to be well worth it.

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@739895 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/rb/ext/binary_protocol_accelerated.c b/lib/rb/ext/binary_protocol_accelerated.c
new file mode 100644
index 0000000..27567fc
--- /dev/null
+++ b/lib/rb/ext/binary_protocol_accelerated.c
@@ -0,0 +1,437 @@
+#include <ruby.h>
+#include <stdbool.h>
+#include <constants.h>
+#include <struct.h>
+
+#define GET_TRANSPORT(obj) rb_ivar_get(obj, transport_ivar_id)
+#define WRITE(obj, data, length) rb_funcall(obj, write_method_id, 1, rb_str_new(data, length))
+#define CHECK_NIL(obj) if (NIL_P(obj)) { rb_raise(rb_eStandardError, "nil argument not allowed!");}
+
+VALUE rb_thrift_binary_proto_native_qmark(VALUE self) {
+  return Qtrue;
+}
+
+
+
+static int VERSION_1;
+static int VERSION_MASK;
+static int BAD_VERSION;
+
+static void write_byte_direct(VALUE trans, int8_t b) {
+  WRITE(trans, (char*)&b, 1);
+}
+
+static void write_i16_direct(VALUE trans, int16_t value) {
+  char data[2];
+  
+  data[1] = value;
+  data[0] = (value >> 8);
+
+  WRITE(trans, data, 2);
+}
+
+static void write_i32_direct(VALUE trans, int32_t value) {
+  char data[4];
+
+  data[3] = value;
+  data[2] = (value >> 8);
+  data[1] = (value >> 16);
+  data[0] = (value >> 24);
+
+  WRITE(trans, data, 4);
+}
+
+
+static void write_i64_direct(VALUE trans, int64_t value) {
+  char data[8];
+
+  data[7] = value;
+  data[6] = (value >> 8);
+  data[5] = (value >> 16);
+  data[4] = (value >> 24);
+  data[3] = (value >> 32);
+  data[2] = (value >> 40);
+  data[1] = (value >> 48);
+  data[0] = (value >> 56);
+
+  WRITE(trans, data, 8);
+}
+
+static void write_string_direct(VALUE trans, VALUE str) {
+  write_i32_direct(trans, RSTRING(str)->len);
+  rb_funcall(trans, write_method_id, 1, str);
+}
+
+//--------------------------------
+// interface writing methods
+//--------------------------------
+
+VALUE rb_thrift_binary_proto_write_message_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_struct_begin(VALUE self, VALUE name) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_struct_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_field_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_map_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_list_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_set_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) {
+  VALUE trans = GET_TRANSPORT(self);
+  write_i32_direct(trans, VERSION_1 | FIX2INT(type));
+  write_string_direct(trans, name);
+  write_i32_direct(trans, FIX2INT(seqid));
+  
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) {
+  VALUE trans = GET_TRANSPORT(self);
+  write_byte_direct(trans, FIX2INT(type));
+  write_i16_direct(trans, FIX2INT(id));
+  
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_field_stop(VALUE self) {
+  write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP);
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size) {
+  VALUE trans = GET_TRANSPORT(self);
+  write_byte_direct(trans, FIX2INT(ktype));
+  write_byte_direct(trans, FIX2INT(vtype));
+  write_i32_direct(trans, FIX2INT(size));
+  
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) {
+  VALUE trans = GET_TRANSPORT(self);
+  write_byte_direct(trans, FIX2INT(etype));
+  write_i32_direct(trans, FIX2INT(size));
+  
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) {
+  rb_thrift_binary_proto_write_list_begin(self, etype, size);
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_bool(VALUE self, VALUE b) {
+  write_byte_direct(GET_TRANSPORT(self), RTEST(b) ? 1 : 0);
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_byte(VALUE self, VALUE byte) {
+  CHECK_NIL(byte);
+  write_byte_direct(GET_TRANSPORT(self), NUM2INT(byte));
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_i16(VALUE self, VALUE i16) {
+  CHECK_NIL(i16);
+  write_i16_direct(GET_TRANSPORT(self), FIX2INT(i16));
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_i32(VALUE self, VALUE i32) {
+  CHECK_NIL(i32);
+  write_i32_direct(GET_TRANSPORT(self), NUM2INT(i32));
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_i64(VALUE self, VALUE i64) {
+  CHECK_NIL(i64);
+  write_i64_direct(GET_TRANSPORT(self), NUM2LL(i64));
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_double(VALUE self, VALUE dub) {
+  CHECK_NIL(dub);
+  // Unfortunately, bitwise_cast doesn't work in C.  Bad C!
+  union {
+    double f;
+    int64_t t;
+  } transfer;
+  transfer.f = RFLOAT(rb_Float(dub))->value;
+  write_i64_direct(GET_TRANSPORT(self), transfer.t);
+
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_write_string(VALUE self, VALUE str) {
+  CHECK_NIL(str);
+  VALUE trans = GET_TRANSPORT(self);
+  // write_i32_direct(trans, RSTRING(str)->len);
+  // rb_funcall(trans, write_method_id, 1, str);
+  write_string_direct(trans, str);
+  return Qnil;
+}
+
+//---------------------------------------
+// interface reading methods
+//---------------------------------------
+
+#define READ(obj, length) rb_funcall(GET_TRANSPORT(obj), read_method_id, 1, INT2FIX(length)) 
+
+VALUE rb_thrift_binary_proto_read_string(VALUE self);
+VALUE rb_thrift_binary_proto_read_byte(VALUE self);
+VALUE rb_thrift_binary_proto_read_i32(VALUE self);
+VALUE rb_thrift_binary_proto_read_i16(VALUE self);
+
+static char read_byte_direct(VALUE self) {
+  return (RSTRING(READ(self, 1))->ptr)[0];
+}
+
+static int16_t read_i16_direct(VALUE self) {
+  VALUE buf = READ(self, 2);
+  return (int16_t)(((uint8_t)(RSTRING(buf)->ptr[1])) | ((uint16_t)((RSTRING(buf)->ptr[0]) << 8)));
+}
+
+static int32_t read_i32_direct(VALUE self) {
+  VALUE buf = READ(self, 4);
+  return ((uint8_t)(RSTRING(buf)->ptr[3])) | 
+    (((uint8_t)(RSTRING(buf)->ptr[2])) << 8) | 
+    (((uint8_t)(RSTRING(buf)->ptr[1])) << 16) | 
+    (((uint8_t)(RSTRING(buf)->ptr[0])) << 24);
+}
+
+static int64_t read_i64_direct(VALUE self) {
+  uint64_t hi = read_i32_direct(self);
+  uint32_t lo = read_i32_direct(self);
+  return (hi << 32) | lo;
+}
+
+static VALUE get_protocol_exception(VALUE code, VALUE message) {
+  VALUE args[2];
+  args[0] = code;
+  args[1] = message;
+  return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
+}
+
+VALUE rb_thrift_binary_proto_read_message_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_struct_begin(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_struct_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_field_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_map_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_list_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_binary_proto_read_set_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) {
+  int version = read_i32_direct(self);
+  if ((version & VERSION_MASK) != VERSION_1) {
+    rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier")));
+  }
+  
+  int type = version & 0x000000ff;
+  VALUE name = rb_thrift_binary_proto_read_string(self);
+  VALUE seqid = rb_thrift_binary_proto_read_i32(self);
+  
+  return rb_ary_new3(3, name, INT2FIX(type), seqid);
+}
+
+VALUE rb_thrift_binary_proto_read_field_begin(VALUE self) {
+  int type = read_byte_direct(self);
+  if (type == TTYPE_STOP) {
+    return rb_ary_new3(3, Qnil, INT2FIX(type), INT2FIX(0));
+  } else {
+    VALUE id = rb_thrift_binary_proto_read_i16(self);
+    return rb_ary_new3(3, Qnil, INT2FIX(type), id);
+  }
+}
+
+VALUE rb_thrift_binary_proto_read_map_begin(VALUE self) {
+  VALUE ktype = rb_thrift_binary_proto_read_byte(self);
+  VALUE vtype = rb_thrift_binary_proto_read_byte(self);
+  VALUE size = rb_thrift_binary_proto_read_i32(self);
+  return rb_ary_new3(3, ktype, vtype, size);
+}
+
+VALUE rb_thrift_binary_proto_read_list_begin(VALUE self) {
+  VALUE etype = rb_thrift_binary_proto_read_byte(self);
+  VALUE size = rb_thrift_binary_proto_read_i32(self);
+  return rb_ary_new3(2, etype, size);
+}
+
+VALUE rb_thrift_binary_proto_read_set_begin(VALUE self) {
+  return rb_thrift_binary_proto_read_list_begin(self);
+}
+
+VALUE rb_thrift_binary_proto_read_bool(VALUE self) {
+  char byte = read_byte_direct(self);
+  return byte == 1 ? Qtrue : Qfalse;
+}
+
+VALUE rb_thrift_binary_proto_read_byte(VALUE self) {
+  return INT2FIX(read_byte_direct(self));
+}
+
+VALUE rb_thrift_binary_proto_read_i16(VALUE self) {
+  return INT2FIX(read_i16_direct(self));
+}
+
+VALUE rb_thrift_binary_proto_read_i32(VALUE self) {
+  return INT2NUM(read_i32_direct(self));
+}
+
+VALUE rb_thrift_binary_proto_read_i64(VALUE self) {
+  return LL2NUM(read_i64_direct(self));
+}
+
+VALUE rb_thrift_binary_proto_read_double(VALUE self) {
+  union {
+    double f;
+    int64_t t;
+  } transfer;
+  transfer.t = read_i64_direct(self);
+  return rb_float_new(transfer.f);
+}
+
+VALUE rb_thrift_binary_proto_read_string(VALUE self) {
+  int size = read_i32_direct(self);
+  return READ(self, size);
+}
+
+void Init_binary_protocol_accelerated() {
+  VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol"));
+  
+  VERSION_1 = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_1")));
+  VERSION_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_MASK")));
+  
+  VALUE bpa_class = rb_define_class_under(thrift_module, "BinaryProtocolAccelerated", thrift_binary_protocol_class);
+  
+  rb_define_method(bpa_class, "native?", rb_thrift_binary_proto_native_qmark, 0);
+  
+  rb_define_method(bpa_class, "write_message_begin", rb_thrift_binary_proto_write_message_begin, 3);
+  rb_define_method(bpa_class, "write_field_begin",   rb_thrift_binary_proto_write_field_begin, 3);
+  rb_define_method(bpa_class, "write_field_stop",    rb_thrift_binary_proto_write_field_stop, 0);
+  rb_define_method(bpa_class, "write_map_begin",     rb_thrift_binary_proto_write_map_begin, 3);
+  rb_define_method(bpa_class, "write_list_begin",    rb_thrift_binary_proto_write_list_begin, 2);
+  rb_define_method(bpa_class, "write_set_begin",     rb_thrift_binary_proto_write_set_begin, 2);
+  rb_define_method(bpa_class, "write_byte",          rb_thrift_binary_proto_write_byte, 1);
+  rb_define_method(bpa_class, "write_bool",          rb_thrift_binary_proto_write_bool, 1);
+  rb_define_method(bpa_class, "write_i16",           rb_thrift_binary_proto_write_i16, 1);
+  rb_define_method(bpa_class, "write_i32",           rb_thrift_binary_proto_write_i32, 1);
+  rb_define_method(bpa_class, "write_i64",           rb_thrift_binary_proto_write_i64, 1);
+  rb_define_method(bpa_class, "write_double",        rb_thrift_binary_proto_write_double, 1);
+  rb_define_method(bpa_class, "write_string",        rb_thrift_binary_proto_write_string, 1);
+  // unused methods
+  rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0);
+  rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1);
+  rb_define_method(bpa_class, "write_struct_end", rb_thrift_binary_proto_write_struct_end, 0);
+  rb_define_method(bpa_class, "write_field_end", rb_thrift_binary_proto_write_field_end, 0);
+  rb_define_method(bpa_class, "write_map_end", rb_thrift_binary_proto_write_map_end, 0);
+  rb_define_method(bpa_class, "write_list_end", rb_thrift_binary_proto_write_list_end, 0);
+  rb_define_method(bpa_class, "write_set_end", rb_thrift_binary_proto_write_set_end, 0);
+  
+
+
+  rb_define_method(bpa_class, "read_message_begin",  rb_thrift_binary_proto_read_message_begin, 0);
+  rb_define_method(bpa_class, "read_field_begin",    rb_thrift_binary_proto_read_field_begin, 0);
+  rb_define_method(bpa_class, "read_map_begin",      rb_thrift_binary_proto_read_map_begin, 0);
+  rb_define_method(bpa_class, "read_list_begin",     rb_thrift_binary_proto_read_list_begin, 0);
+  rb_define_method(bpa_class, "read_set_begin",      rb_thrift_binary_proto_read_set_begin, 0);
+  rb_define_method(bpa_class, "read_byte",           rb_thrift_binary_proto_read_byte, 0);
+  rb_define_method(bpa_class, "read_bool",           rb_thrift_binary_proto_read_bool, 0);
+  rb_define_method(bpa_class, "read_i16",            rb_thrift_binary_proto_read_i16, 0);
+  rb_define_method(bpa_class, "read_i32",            rb_thrift_binary_proto_read_i32, 0);
+  rb_define_method(bpa_class, "read_i64",            rb_thrift_binary_proto_read_i64, 0);
+  rb_define_method(bpa_class, "read_double",         rb_thrift_binary_proto_read_double, 0);
+  rb_define_method(bpa_class, "read_string",         rb_thrift_binary_proto_read_string, 0);
+  // unused methods
+  rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0);
+  rb_define_method(bpa_class, "read_struct_begin", rb_thift_binary_proto_read_struct_begin, 0);
+  rb_define_method(bpa_class, "read_struct_end", rb_thift_binary_proto_read_struct_end, 0);
+  rb_define_method(bpa_class, "read_field_end", rb_thift_binary_proto_read_field_end, 0);
+  rb_define_method(bpa_class, "read_map_end", rb_thift_binary_proto_read_map_end, 0);
+  rb_define_method(bpa_class, "read_list_end", rb_thift_binary_proto_read_list_end, 0);
+  rb_define_method(bpa_class, "read_set_end", rb_thift_binary_proto_read_set_end, 0);
+
+  // set up native method table
+  native_proto_method_table *npmt;
+  npmt = ALLOC(native_proto_method_table);
+
+  npmt->write_field_begin = rb_thrift_binary_proto_write_field_begin;
+  npmt->write_field_stop = rb_thrift_binary_proto_write_field_stop;
+  npmt->write_map_begin = rb_thrift_binary_proto_write_map_begin;
+  npmt->write_list_begin = rb_thrift_binary_proto_write_list_begin;
+  npmt->write_set_begin = rb_thrift_binary_proto_write_set_begin;
+  npmt->write_byte = rb_thrift_binary_proto_write_byte;
+  npmt->write_bool = rb_thrift_binary_proto_write_bool;
+  npmt->write_i16 = rb_thrift_binary_proto_write_i16;
+  npmt->write_i32 = rb_thrift_binary_proto_write_i32;
+  npmt->write_i64 = rb_thrift_binary_proto_write_i64;
+  npmt->write_double = rb_thrift_binary_proto_write_double;
+  npmt->write_string = rb_thrift_binary_proto_write_string;
+  npmt->write_message_end = rb_thrift_binary_proto_write_message_end;
+  npmt->write_struct_begin = rb_thrift_binary_proto_write_struct_begin;
+  npmt->write_struct_end = rb_thrift_binary_proto_write_struct_end;
+  npmt->write_field_end = rb_thrift_binary_proto_write_field_end;
+  npmt->write_map_end = rb_thrift_binary_proto_write_map_end;
+  npmt->write_list_end = rb_thrift_binary_proto_write_list_end;
+  npmt->write_set_end = rb_thrift_binary_proto_write_set_end;
+
+  npmt->read_message_begin = rb_thrift_binary_proto_read_message_begin;
+  npmt->read_field_begin = rb_thrift_binary_proto_read_field_begin;
+  npmt->read_map_begin = rb_thrift_binary_proto_read_map_begin;
+  npmt->read_list_begin = rb_thrift_binary_proto_read_list_begin;
+  npmt->read_set_begin = rb_thrift_binary_proto_read_set_begin;
+  npmt->read_byte = rb_thrift_binary_proto_read_byte;
+  npmt->read_bool = rb_thrift_binary_proto_read_bool;
+  npmt->read_i16 = rb_thrift_binary_proto_read_i16;
+  npmt->read_i32 = rb_thrift_binary_proto_read_i32;
+  npmt->read_i64 = rb_thrift_binary_proto_read_i64;
+  npmt->read_double = rb_thrift_binary_proto_read_double;
+  npmt->read_string = rb_thrift_binary_proto_read_string;
+  npmt->read_message_end = rb_thrift_binary_proto_read_message_end;
+  npmt->read_struct_begin = rb_thift_binary_proto_read_struct_begin;
+  npmt->read_struct_end = rb_thift_binary_proto_read_struct_end;
+  npmt->read_field_end = rb_thift_binary_proto_read_field_end;
+  npmt->read_map_end = rb_thift_binary_proto_read_map_end;
+  npmt->read_list_end = rb_thift_binary_proto_read_list_end;
+  npmt->read_set_end = rb_thift_binary_proto_read_set_end;
+  
+  VALUE method_table_object = Data_Wrap_Struct(rb_cObject, 0, free, npmt);
+  rb_const_set(bpa_class, rb_intern("@native_method_table"), method_table_object);
+}
\ No newline at end of file
diff --git a/lib/rb/ext/binary_protocol_accelerated.h b/lib/rb/ext/binary_protocol_accelerated.h
new file mode 100644
index 0000000..4d3517b
--- /dev/null
+++ b/lib/rb/ext/binary_protocol_accelerated.h
@@ -0,0 +1,2 @@
+
+void Init_binary_protocol_accelerated();
\ No newline at end of file
diff --git a/lib/rb/ext/binaryprotocolaccelerated.c b/lib/rb/ext/binaryprotocolaccelerated.c
deleted file mode 100644
index 1da7a3d..0000000
--- a/lib/rb/ext/binaryprotocolaccelerated.c
+++ /dev/null
@@ -1,1239 +0,0 @@
-// Half of this file comes from contributions from Nitay Joffe (nitay@powerset.com)
-// Much of the rest (almost) directly ported (or pulled) from thrift-py's fastbinary.c
-// Everything else via Kevin Clark (kevin@powerset.com)
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <ruby.h>
-#include <st.h>
-#include <netinet/in.h>
-
-// #define __DEBUG__
-
-#ifndef HAVE_STRLCPY
-
-static
-size_t
-strlcpy (char *dst, const char *src, size_t dst_sz)
-{
-    size_t n;
-
-    for (n = 0; n < dst_sz; n++) {
-      if ((*dst++ = *src++) == '\0')
-        break;
-    }
-
-    if (n < dst_sz)
-      return n;
-    if (n > 0)
-      *(dst - 1) = '\0';
-    return n + strlen (src);
-}
-
-#endif
-
-#define dbg() fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__)
-
-
-// TODO (kevinclark): This was here from the patch/python. Not sure
-// If it's actually that big a pain. Need to look into pulling
-// From the right place
-
-// Stolen out of TProtocol.h.
-// It would be a huge pain to have both get this from one place.
-
-enum TType {
-  T_STOP       = 0,
-  T_BOOL       = 2,
-  T_BYTE       = 3,
-  T_I16        = 6,
-  T_I32        = 8,
-  T_I64        = 10,
-  T_DBL        = 4,
-  T_STR        = 11,
-  T_STRCT      = 12,
-  T_MAP        = 13,
-  T_SET        = 14,
-  T_LIST       = 15
-  // T_VOID       = 1,
-  // T_I08        = 3,
-  // T_U64        = 9,
-  // T_UTF7       = 11,
-  // T_UTF8       = 16,
-  // T_UTF16      = 17
-};
-
-#define IS_CONTAINER(x) (x == T_MAP || x == T_SET || x == T_LIST)
-
-// Same comment as the enum.  Sorry.
-#ifdef HAVE_ENDIAN_H
-#include <endian.h>
-#endif
-
-#ifndef __BYTE_ORDER
-# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
-#  define __BYTE_ORDER BYTE_ORDER
-#  define __LITTLE_ENDIAN LITTLE_ENDIAN
-#  define __BIG_ENDIAN BIG_ENDIAN
-# else
-#  error "Cannot determine endianness"
-# endif
-#endif
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-# define ntohll(n) (n)
-# define htonll(n) (n)
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-# if defined(__GNUC__) && defined(__GLIBC__)
-#  include <byteswap.h>
-#  define ntohll(n) bswap_64(n)
-#  define htonll(n) bswap_64(n)
-# else /* GNUC & GLIBC */
-#  define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
-#  define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
-# endif /* GNUC & GLIBC */
-#else /* __BYTE_ORDER */
-# error "Can't define htonll or ntohll!"
-#endif
-
-
-// -----------------------------------------------------------------------------
-// Cached interned strings and such
-// -----------------------------------------------------------------------------
-
-static VALUE class_tbpa;
-static VALUE m_thrift;
-static VALUE rb_cSet;
-static ID type_sym;
-static ID class_sym;
-static ID key_sym;
-static ID value_sym;
-static ID element_sym;
-static ID name_sym;
-static ID fields_id;
-static ID consume_bang_id;
-static ID string_buffer_id;
-static ID borrow_id;
-static ID keys_id;
-static ID entries_id;
-
-static const uint32_t VERSION_MASK = 0xffff0000;
-static const uint32_t VERSION_1 = 0x80010000;
-
-// -----------------------------------------------------------------------------
-// Structs so I don't have to keep calling rb_hash_aref
-// -----------------------------------------------------------------------------
-
-// { :type => field[:type],
-//   :class => field[:class],
-//   :key => field[:key],
-//   :value => field[:value],
-//   :element => field[:element] }
-
-struct _thrift_map;
-struct _field_spec;
-
-typedef union {
-  VALUE class;
-  struct _thrift_map* map;
-  struct _field_spec* element;
-} container_data;
-
-typedef struct _field_spec {
-  int type;
-  char* name;
-  container_data data;
-} field_spec;
-
-typedef struct _thrift_map {
-  field_spec* key;
-  field_spec* value; 
-} thrift_map;
-
-
-static void free_field_spec(field_spec* spec) {
-  switch(spec->type) {
-    case T_LIST:
-    case T_SET:
-      free_field_spec(spec->data.element);
-      break;
-    
-    case T_MAP:
-      free_field_spec(spec->data.map->key);
-      free_field_spec(spec->data.map->value);
-      free(spec->data.map);
-      break;
-  }
-  
-  free(spec);
-}
-
-// Parses a ruby field spec into a C struct
-//
-// Simple fields look like:
-// { :name => .., :type => .. }
-// Structs add the :class attribute
-// Maps adds :key and :value attributes, field specs
-// Lists and Sets add an :element, a field spec
-static field_spec* parse_field_spec(VALUE field_data) {
-  int type = NUM2INT(rb_hash_aref(field_data, type_sym));
-  VALUE name = rb_hash_aref(field_data, name_sym);
-  field_spec* spec = (field_spec *) malloc(sizeof(field_spec));
-
-#ifdef __DEBUG__ // No need for this in prod since I set all the fields
-  bzero(spec, sizeof(field_spec));
-#endif
-
-  spec->type = type;
-  
-  if (!NIL_P(name)) {
-    spec->name = StringValuePtr(name);
-  } else {
-    spec->name = NULL;
-  }
-  
-  switch(type) {
-    case T_STRCT: {
-      spec->data.class = rb_hash_aref(field_data, class_sym);
-      break;
-    }
-    
-    case T_MAP: {
-      VALUE key_fields = rb_hash_aref(field_data, key_sym);
-      VALUE value_fields = rb_hash_aref(field_data, value_sym);
-      thrift_map* map = (thrift_map *) malloc(sizeof(thrift_map));
-      
-      map->key = parse_field_spec(key_fields);
-      map->value = parse_field_spec(value_fields);
-      spec->data.map = map;
-      
-      break;
-    }
-    
-    case T_LIST: 
-    case T_SET:
-    {
-      VALUE list_fields = rb_hash_aref(field_data, element_sym);
-      spec->data.element = parse_field_spec(list_fields);
-      break;
-    }
-  }
-  
-  return spec;
-}
-
-
-// -----------------------------------------------------------------------------
-// Serialization routines
-// -----------------------------------------------------------------------------
-
-
-// write_*(VALUE buf, ...) takes a value and adds it to a Ruby string buffer,
-// in network order
-static void write_byte(VALUE buf, int8_t val) {
-  rb_str_buf_cat(buf, (char*)&val, sizeof(int8_t));
-}
-
-static void write_i16(VALUE buf, int16_t val) {
-  int16_t net = (int16_t)htons(val);
-  rb_str_buf_cat(buf, (char*)&net, sizeof(int16_t));
-}
-
-static void write_i32(VALUE buf, int32_t val) {
-  int32_t net = (int32_t)htonl(val);
-  rb_str_buf_cat(buf, (char*)&net, sizeof(int32_t));
-}
-
-static void write_i64(VALUE buf, int64_t val) {
-  int64_t net = (int64_t)htonll(val);
-  rb_str_buf_cat(buf, (char*)&net, sizeof(int64_t));
-}
-
-static void write_double(VALUE buf, double dub) {
-  // Unfortunately, bitwise_cast doesn't work in C.  Bad C!
-  union {
-    double f;
-    int64_t t;
-  } transfer;
-  transfer.f = dub;
-  write_i64(buf, transfer.t);
-}
-
-static void write_string(VALUE buf, char* str, size_t len) {
-  write_i32(buf, len);
-  rb_str_buf_cat(buf, str, len);
-}
-
-// Some functions macro'd out because they're nops for the binary protocol
-// but placeholders were desired in case things change
-#define write_struct_begin(buf)
-#define write_struct_end(buf)
-
-static void write_field_begin(VALUE buf, char* name, int type, int fid) {
-#ifdef __DEBUG__
-  fprintf(stderr, "Writing field beginning: %s %d %d\n", name, type, fid);
-#endif
-
-  write_byte(buf, (int8_t)type);
-  write_i16(buf, (int16_t)fid);
-}
-
-#define write_field_end(buf)
-
-static void write_field_stop(VALUE buf) {
-  write_byte(buf, T_STOP);
-}
-
-static void write_map_begin(VALUE buf, int8_t ktype, int8_t vtype, int32_t sz) {
-  write_byte(buf, ktype);
-  write_byte(buf, vtype);
-  write_i32(buf, sz);
-}
-
-#define write_map_end(buf);
-
-static void write_list_begin(VALUE buf, int type, int sz) {
-  write_byte(buf, type);
-  write_i32(buf, sz);
-}
-
-#define write_list_end(buf)
-
-static void write_set_begin(VALUE buf, int type, int sz) {
-  write_byte(buf, type);
-  write_i32(buf, sz);
-}
-
-#define write_set_end(buf)
-
-static void binary_encoding(VALUE buf, VALUE obj, int type);
-
-// Handles container types: Map, Set, List
-static void write_container(VALUE buf, VALUE value, field_spec* spec) {
-  int sz, i;
-  
-  switch(spec->type) {
-    case T_MAP: {
-      VALUE keys;
-      VALUE key;
-      VALUE val;
-
-      Check_Type(value, T_HASH);
-      
-      keys = rb_funcall(value, keys_id, 0);
-      
-      sz = RARRAY(keys)->len;
-      
-      write_map_begin(buf, spec->data.map->key->type, spec->data.map->value->type, sz);
-      
-      for (i = 0; i < sz; i++) {
-        key = rb_ary_entry(keys, i);
-        val = rb_hash_aref(value, key);
-        
-        if (IS_CONTAINER(spec->data.map->key->type)) {
-          write_container(buf, key, spec->data.map->key);
-        } else {
-          binary_encoding(buf, key, spec->data.map->key->type);
-        }
-        
-        if (IS_CONTAINER(spec->data.map->value->type)) {
-          write_container(buf, val, spec->data.map->value);
-        } else {
-          binary_encoding(buf, val, spec->data.map->value->type);
-        }
-      }
-      
-      write_map_end(buf);
-
-      break;
-    }
-    
-    case T_LIST: {
-      Check_Type(value, T_ARRAY);
-
-      sz = RARRAY(value)->len;
-      
-      write_list_begin(buf, spec->data.element->type, sz);
-      for (i = 0; i < sz; ++i) {
-        VALUE val = rb_ary_entry(value, i);
-        if (IS_CONTAINER(spec->data.element->type)) {
-          write_container(buf, val, spec->data.element);
-        } else {
-          binary_encoding(buf, val, spec->data.element->type);
-        }
-      }
-      write_list_end(buf);
-      break;
-    }
-
-    case T_SET: {
-      VALUE items;
-
-      if (TYPE(value) == T_ARRAY) {
-        items = value;
-      } else {        
-        if (rb_cSet == CLASS_OF(value)) {
-          items = rb_funcall(value, entries_id, 0);
-        } else {
-          Check_Type(value, T_HASH);
-          items = rb_funcall(value, keys_id, 0);
-        }
-      }
-
-      sz = RARRAY(items)->len;
-      
-      write_set_begin(buf, spec->data.element->type, sz);
-      
-      for (i = 0; i < sz; i++) {
-        VALUE val = rb_ary_entry(items, i);
-        if (IS_CONTAINER(spec->data.element->type)) {
-          write_container(buf, val, spec->data.element);
-        } else {
-          binary_encoding(buf, val, spec->data.element->type);
-        }
-      }
-      
-      write_set_end(buf);
-      break;
-    }
-  }
-}
-
-// Takes the field id, data to be encoded, buffer and enclosing object
-// to be encoded. buf and obj passed as a ruby array for rb_hash_foreach.
-// TODO(kevinclark): See if they can be passed individually to avoid object
-// creation
-static int encode_field(VALUE fid, VALUE data, VALUE ary) {
-  field_spec *spec = parse_field_spec(data);
-  
-  VALUE buf = rb_ary_entry(ary, 0);
-  VALUE obj = rb_ary_entry(ary, 1);
-  char name_buf[128];
-  
-  name_buf[0] = '@';
-  strlcpy(&name_buf[1], spec->name, sizeof(name_buf) - 1);
-  
-  VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
-  
-  if (NIL_P(value)) {
-    free_field_spec(spec);
-    return 0;
-  }
-     
-  write_field_begin(buf, spec->name, spec->type, NUM2INT(fid));
-  
-  if (IS_CONTAINER(spec->type)) {
-    write_container(buf, value, spec);
-  } else {
-    binary_encoding(buf, value, spec->type);
-  }
-  write_field_end(buf);
-  
-  free_field_spec(spec);
-  
-  return 0;
-}
-
-// -----------------------------------------------------------------------------
-// TFastBinaryProtocol's main encoding loop
-// -----------------------------------------------------------------------------
-
-static void binary_encoding(VALUE buf, VALUE obj, int type) {
-#ifdef __DEBUG__
-  rb_p(rb_str_new2("Encoding binary (buf, obj, type)"));
-  rb_p(rb_inspect(buf));
-  rb_p(rb_inspect(obj));
-  rb_p(rb_inspect(INT2FIX(type)));
-#endif
-
-  switch(type) {
-    case T_BOOL:
-      if RTEST(obj) {
-        write_byte(buf, 1);
-      }
-      else {
-        write_byte(buf, 0);
-      }
-      
-      break;
-    
-    case T_BYTE:
-      write_byte(buf, NUM2INT(obj));
-      break;
-    
-    case T_I16:
-      write_i16(buf, NUM2INT(obj));
-      break;
-    
-    case T_I32:
-      write_i32(buf, NUM2INT(obj));
-      break;
-    
-    case T_I64:
-      write_i64(buf, rb_num2ll(obj));
-      break;
-    
-    case T_DBL:
-      write_double(buf, NUM2DBL(obj));
-      break;
-
-    case T_STR: {
-      // make sure to call StringValuePtr before calling RSTRING
-      char *ptr = StringValuePtr(obj);
-      write_string(buf, ptr, RSTRING(obj)->len);
-      break;
-    }
-          
-    case T_STRCT: {
-      // rb_hash_foreach has to take args as a ruby array
-      VALUE args = rb_ary_new3(2, buf, obj);
-      VALUE fields = rb_const_get(CLASS_OF(obj), fields_id);
-      
-      write_struct_begin(buf);
-      
-      rb_hash_foreach(fields, encode_field, args);
-      
-      write_field_stop(buf);
-      write_struct_end(buf);
-      break;
-    }
-    
-    default: {
-      rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", type);
-    }
-  }
-}
-
-// obj is always going to be a TSTRCT
-static VALUE tbpa_encode_binary(VALUE self, VALUE obj) {
-  VALUE buf = rb_str_buf_new(1024);
-  binary_encoding(buf, obj, T_STRCT);
-  return buf;
-}
-
-
-// -----------------------------------------------------------------------------
-// Read stuff
-// -----------------------------------------------------------------------------
-
-typedef struct {
-  char* name;
-  int8_t type;
-  int16_t id;
-} field_header;
-
-typedef struct {
-  int8_t key_type;
-  int8_t val_type;
-  int num_entries;
-} map_header;
-
-typedef struct {
-  int8_t type;
-  int num_elements;
-} list_header;
-
-typedef list_header set_header;
-
-typedef struct {
-  char* data;
-  int pos;
-  int len;
-  VALUE trans;
-} decode_buffer;
-
-typedef struct {
-  char* ptr;
-  int len;
-} thrift_string;
-
-#define read_struct_begin(buf)
-#define read_struct_end(buf)
-
-// This prototype is required to be able to run a call through rb_protect
-// which rescues from ruby exceptions
-static VALUE protectable_consume(VALUE args) {
-  VALUE trans = rb_ary_entry(args, 0);
-  VALUE size = rb_ary_entry(args, 1);
-  
-  return rb_funcall(trans, consume_bang_id, 1, size);
-}
-
-// Clears size bytes from the transport's string buffer
-static bool consume(decode_buffer* buf, int32_t size) {
-  if (size != 0) {
-    VALUE ret;
-    VALUE args = rb_ary_new3(2, buf->trans, INT2FIX(size));
-    int status = 0;
-    
-    ret = rb_protect(protectable_consume, args, &status);
-    
-    if (status) {
-      return false;
-    } else {
-      return true;
-    }
-  }
-  
-  // Nothing to consume, we're all good
-  return true;
-}
-
-// This prototype is required to be able to run a call through rb_protect
-// which rescues from ruby exceptions
-static VALUE protectable_borrow(VALUE args) {
-  VALUE trans = rb_ary_entry(args, 0);
-  
-  switch(RARRAY(args)->len) {
-    case 1:
-      return rb_funcall(trans, borrow_id, 0);
-    
-    case 2: {
-      VALUE size = rb_ary_entry(args, 1);
-      return rb_funcall(trans, borrow_id, 1, size);
-    }
-  }
-  
-  return Qnil;
-}
-
-// Calls into the transport to get the available string buffer
-static bool borrow(decode_buffer* buf, int32_t size, VALUE* dst) {
-  int status = 0;
-  VALUE args;
-  
-  if (size == 0) {
-    args = rb_ary_new3(1, buf->trans);
-  } else {
-    args = rb_ary_new3(2, buf->trans, INT2FIX(size));
-  }
-
-  *dst = rb_protect(protectable_borrow, args, &status);
-  
-  return (status == 0);
-}
-
-// Refills the buffer by calling borrow. If buf->pos is nonzero that number of bytes
-// is cleared through consume.
-//
-// returns: 0 on success, non-zero on failure. On error buf is unchanged.
-static int fill_buffer(decode_buffer* buf, int32_t req_len) {
-  VALUE refill;
-  
-  if (!consume(buf, buf->pos)) {
-    return -1;
-  }
-
-  if (!borrow(buf, req_len, &refill)) {
-    return -2;
-  }
-  
-  buf->data = StringValuePtr(refill);
-  buf->len = RSTRING(refill)->len;
-  buf->pos = 0;
-  
-  return 0;
-}
-
-
-// read_bytes pulls a number of bytes (size) from the buffer, refilling if needed,
-// and places them in dst. This should _always_ be used used when reading from the buffer
-// or buffered transports will be upset with you.
-static bool read_bytes(decode_buffer* buf, void* dst, size_t size) {
-  int avail = (buf->len - buf->pos);
-  
-  if (size <= avail) {
-    memcpy(dst, buf->data + buf->pos, size);
-    buf->pos += size;
-  } else {
-    
-    if (avail > 0) {
-      // Copy what we can
-      memcpy(dst, buf->data + buf->pos, avail);
-      buf->pos += avail;
-    }
-
-    if (fill_buffer(buf, size - avail) < 0) {
-      return false;
-    }
-    
-    memcpy(dst + avail, buf->data, size - avail);
-    buf->pos += size - avail;
-  }
-  
-  return true;
-}
-
-// -----------------------------------------------------------------------------
-// Helpers for grabbing specific types from the buffer
-// -----------------------------------------------------------------------------
-
-static bool read_byte(decode_buffer* buf, int8_t* data) {
-  return read_bytes(buf, data, sizeof(int8_t));
-}
-
-static bool read_int16(decode_buffer* buf, int16_t* data) {
-  bool success = read_bytes(buf, data, sizeof(int16_t));
-  *data = ntohs(*data);
-  
-  return success;
-}
-
-static bool read_int32(decode_buffer* buf, int32_t* data) {
-  bool success = read_bytes(buf, data, sizeof(int32_t));
-  *data = ntohl(*data);
-  
-  return success;
-}
-
-static bool read_int64(decode_buffer* buf, int64_t* data) {
-  bool success = read_bytes(buf, data, sizeof(int64_t));
-  *data = ntohll(*data);
-  
-  return success;
-}
-
-static bool read_double(decode_buffer* buf, double* data) {
-  return read_int64(buf, (int64_t*)data);
-}
-
-static bool read_string(decode_buffer* buf, VALUE* data) {
-  int len;
-  
-  if (!read_int32(buf, &len)) {
-    return false;
-  }
-  
-  if (buf->len - buf->pos >= len) {
-    *data = rb_str_new(buf->data + buf->pos, len);
-    buf->pos += len;
-  } 
-  else {
-    char* str;
-    
-    if ((str = (char*) malloc(len)) == NULL) {
-      return false;
-    }
-    
-    if (!read_bytes(buf, str, len)) {
-      free(str);
-      return false;
-    }
-    
-    *data = rb_str_new(str, len);
-    
-    free(str);
-  }
-  
-  return true;
-}
-
-static bool read_field_begin(decode_buffer* buf, field_header* header) {
-#ifdef __DEBUG__ // No need for this in prod since I set all the fields
-  bzero(header, sizeof(field_header));
-#endif
-
-  header->name = NULL;
-  
-  if (!read_byte(buf, &header->type)) {
-    return false;
-  }
-  
-  if (header->type == T_STOP) {
-    header->id = 0;
-  } else {
-    if (!read_int16(buf, &header->id)) {
-      return false;
-    }
-  }
-  
-  return true;
-}
-
-#define read_field_end(buf)
-
-static bool read_map_begin(decode_buffer* buf, map_header* header) {
-#ifdef __DEBUG__ // No need for this in prod since I set all the fields
-  bzero(header, sizeof(map_header));
-#endif
-  
-  return (read_byte(buf, &header->key_type) && 
-          read_byte(buf, &header->val_type) &&
-          read_int32(buf, &header->num_entries));
-}
-
-#define read_map_end(buf)
-
-static bool read_list_begin(decode_buffer* buf, list_header* header) {
-#ifdef __DEBUG__ // No need for this in prod since I set all the fields
-  bzero(header, sizeof(list_header));
-#endif
-  
-  if (!read_byte(buf, &header->type) || !read_int32(buf, &header->num_elements)) {
-    return false;
-  } else {
-    return true;
-  }
-}
-
-#define read_list_end(buf)
-
-#define read_set_begin read_list_begin
-#define read_set_end read_list_end
-
-
-// High level reader function with ruby type coercion
-static bool read_type(int type, decode_buffer* buf, VALUE* dst) {
-  switch(type) {
-    case T_BOOL: {
-      int8_t byte;
-      
-      if (!read_byte(buf, &byte)) {
-        return false;
-      }
-      
-      if (0 == byte) {
-        *dst = Qfalse;
-      } else {
-        *dst = Qtrue;
-      }
-      
-      break;
-    }
-    
-    case T_BYTE: {
-      int8_t byte;
-
-      if (!read_byte(buf, &byte)) {
-        return false;
-      }
-
-      *dst = INT2FIX(byte);
-      break;
-    }
-    
-    case T_I16: {
-      int16_t i16;
-      
-      if (!read_int16(buf, &i16)) {
-        return false;
-      }
-      
-      *dst = INT2FIX(i16);
-      break;
-    }
-
-    case T_I32: {
-      int32_t i32;
-      
-      if (!read_int32(buf, &i32)) {
-        return false;
-      }
-      
-      *dst = INT2NUM(i32);
-      break;
-    }
-
-    case T_I64: {
-      int64_t i64;
-      
-      if (!read_int64(buf, &i64)) {
-        return false;
-      }
-      
-      *dst = rb_ll2inum(i64);
-      break;
-    }
-    
-    case T_DBL: {
-      double dbl;
-      
-      if (!read_double(buf, &dbl)) {
-        return false;
-      }
-      
-      *dst = rb_float_new(dbl);
-      break;
-    }
-
-    case T_STR: {
-      VALUE str;
-      
-      if (!read_string(buf, &str)) {
-        return false;
-      }
-      
-      *dst = str;
-      break;
-    }
-  }
-  
-  return true;
-}
-
-// TODO(kevinclark): Now that read_string does a malloc,
-// This maybe could be modified to avoid that, and the type coercion
-
-// Read the bytes but don't do anything with the value
-static bool skip_type(int type, decode_buffer* buf) {
-  switch (type) {
-    case T_STRCT:
-      read_struct_begin(buf);
-      while (true) {
-        field_header header;
-
-        if (!read_field_begin(buf, &header)) {
-          return false;
-        }
-
-        if (header.type == T_STOP) {
-          break;
-        }
-
-        if (!skip_type(header.type, buf)) {
-          return false;
-        }
-
-        read_field_end(buf);
-      }
-      read_struct_end(buf);
-
-      break;
-
-    case T_MAP: {
-      int i;
-      map_header header;
-
-      if (!read_map_begin(buf, &header)) {
-        return false;
-      }
-
-      for (i = 0; i < header.num_entries; ++i) {
-        if (!skip_type(header.key_type, buf)) {
-          return false;
-        }
-        if (!skip_type(header.val_type, buf)) {
-          return false;
-        }
-      }
-
-      read_map_end(buf);
-      break;
-    }
-
-    case T_SET: {
-      int i;
-      set_header header;
-
-      if (!read_set_begin(buf, &header)) {
-        return false;
-      }
-
-      for (i = 0; i < header.num_elements; ++i) {
-        if (!skip_type(header.type, buf)) {
-          return false;
-        }
-      }
-
-      read_set_end(buf);
-      break;
-    }
-
-    case T_LIST: {
-      int i;
-      list_header header;
-
-      if (!read_list_begin(buf, &header)) {
-        return false;
-      }
-
-      for (i = 0; i < header.num_elements; ++i) {
-        if (!skip_type(header.type, buf)) {
-          return false;
-        }
-      }
-
-      read_list_end(buf);
-      break;
-    }
-
-    default: {
-      VALUE v;
-      if (!read_type(type, buf, &v)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-
-static VALUE read_struct(VALUE obj, decode_buffer* buf);
-
-// Read the right thing from the buffer given the field spec
-// and return the ruby object
-static bool read_field(decode_buffer* buf, field_spec* spec, VALUE* dst) {
-  switch (spec->type) {
-    case T_STRCT: {
-      VALUE obj = rb_class_new_instance(0, NULL, spec->data.class);
-      
-      *dst = read_struct(obj, buf);
-      break;
-    }
-    
-    case T_MAP: {
-      map_header hdr;
-      VALUE hsh;
-      int i;
-      
-      read_map_begin(buf, &hdr); 
-      hsh = rb_hash_new();
-      
-      for (i = 0; i < hdr.num_entries; ++i) {
-        VALUE key, val;
-        
-        if (!read_field(buf, spec->data.map->key, &key)) {
-          return false;
-        }
-        
-        if (!read_field(buf, spec->data.map->value, &val)) {
-          return false;
-        }
-        
-        rb_hash_aset(hsh, key, val);
-      }
-      
-      read_map_end(buf);
-      
-      *dst = hsh;
-      break;
-    }
-    
-    case T_LIST: {
-      list_header hdr;
-      VALUE arr, element;
-      int i;
-      
-      read_list_begin(buf, &hdr);
-      arr = rb_ary_new2(hdr.num_elements);
-      
-      for (i = 0; i < hdr.num_elements; ++i) {
-        if (!read_field(buf, spec->data.element, &element)) {
-          return false;
-        }
-
-        rb_ary_push(arr, element);
-      }
-      
-      read_list_end(buf);
-      
-      *dst = arr;
-      break;
-    }
-    
-    case T_SET: {
-      VALUE items, item;
-      set_header hdr;
-      int i;
-      
-      read_set_begin(buf, &hdr);
-      items = rb_ary_new2(hdr.num_elements);
-      
-      for (i = 0; i < hdr.num_elements; ++i) {
-        if (!read_field(buf, spec->data.element, &item)) {
-          return false;
-        }
-        
-        rb_ary_push(items, item);
-      }
-      
-      *dst = rb_class_new_instance(1, &items, rb_cSet);
-      break;
-    }
-    
-    
-    default:
-      return read_type(spec->type, buf, dst);
-  }
-  
-  return true;
-}
-
-static void handle_read_error() {
-  // If it was an exception, reraise
-  if (!NIL_P(ruby_errinfo)) {
-    rb_exc_raise(ruby_errinfo);
-  } else {
-    // Something else went wrong, no idea what would call this yet
-    // So far, the only thing to cause failures underneath is ruby
-    // exceptions. Follow up on this regularly -- Kevin Clark (TODO)
-    rb_raise(rb_eStandardError, "[BUG] Something went wrong in the field reading, but not a ruby exception");
-  }
-}
-
-// Fill in the instance variables in an object (thrift struct)
-// from the decode buffer
-static VALUE read_struct(VALUE obj, decode_buffer* buf) {
-  VALUE field;
-  field_header f_header;
-  VALUE value = Qnil;
-  VALUE fields = rb_const_get(CLASS_OF(obj), fields_id);
-  field_spec* spec;
-  char name_buf[128];
-    
-  read_struct_begin(buf);
-  
-  while(true) {
-    if (!read_field_begin(buf, &f_header)) {
-      handle_read_error();
-    }
-    
-    if (T_STOP == f_header.type) {
-      break;
-    }
-    
-    field = rb_hash_aref(fields, INT2FIX(f_header.id));
-    
-    if (NIL_P(field)) {
-      if (!skip_type(f_header.type, buf)) {
-        handle_read_error();
-        return Qnil;
-      }
-    } 
-    else {
-      spec = parse_field_spec(field);
-
-      if (spec->type != f_header.type) {
-        if (!skip_type(spec->type, buf)) {
-          free_field_spec(spec);
-          handle_read_error();
-          return Qnil;
-        }
-      } else {
-        // Read busted somewhere (probably borrow/consume), bail
-        if (!read_field(buf, spec, &value)) {
-          free_field_spec(spec);
-          handle_read_error();
-          return Qnil;
-        }
-        
-        name_buf[0] = '@';
-        strlcpy(&name_buf[1], spec->name, sizeof(name_buf) - 1);
-        
-        rb_iv_set(obj, name_buf, value);
-      }
-      
-      free_field_spec(spec);
-    }
-    
-    read_field_end(buf);
-  }
-  
-  read_struct_end(buf);
-  
-  return obj;
-}
-
-
-// Takes an object and transport, and decodes the values in the transport's
-// buffer to fill the object.
-static VALUE tbpa_decode_binary(VALUE self, VALUE obj, VALUE transport) {
-  decode_buffer buf;
-  VALUE ret_val;
-
-  buf.pos = 0;    // This needs to be set so an arbitrary number of bytes isn't consumed
-  buf.trans = transport;       // We need to hold this so the buffer can be refilled
-  
-  if (fill_buffer(&buf, 0) < 0) {
-    handle_read_error();
-    return Qnil;
-  }
-
-#ifdef __DEBUG__
-  rb_p(rb_str_new2("Running decode binary with data:"));
-  rb_p(rb_inspect(rb_str_new2(buf.data)));
-#endif
- 
-  ret_val = read_struct(obj, &buf);
-  
-  // Consume whatever was read
-  consume(&buf, buf.pos);
-  
-  return ret_val;
-}
-
-// -----------------------------------------------------------------------------
-// These methods are used by the thrift library and need to handled
-// seperately from encode and decode
-// -----------------------------------------------------------------------------
-
-// Read the message header and return it as a ruby array
-static VALUE tbpa_read_message_begin(VALUE self) {
-  decode_buffer buf;
-  int32_t version, seqid;
-  int8_t type;
-  VALUE name;
-  
-  VALUE trans = rb_iv_get(self, "@trans");
-  
-  buf.pos = 0;              // This needs to be set so fill_buffer doesn't consume
-  buf.trans = trans;        // We need to hold this so the buffer can be refilled
-  
-
-  if (fill_buffer(&buf, 0) < 0 || !read_int32(&buf, &version)) {
-    // Consume whatever was read
-    consume(&buf, buf.pos);
-    handle_read_error();
-    return Qnil;
-  }
-  
-  if ((version & VERSION_MASK) != VERSION_1) {
-    VALUE tprotocol_exception = rb_const_get(m_thrift, rb_intern("ProtocolException"));
-    VALUE exception = rb_funcall(tprotocol_exception, rb_intern("new"), 2, rb_const_get(tprotocol_exception, rb_intern("BAD_VERSION")), rb_str_new2("Missing version identifier"));
-    rb_exc_raise(exception);
-  }
-  
-  type = version & 0x000000ff;
-  
-  if (!read_string(&buf, &name) || !read_int32(&buf, &seqid)) {
-    // Consume whatever was read
-    consume(&buf, buf.pos);
-    handle_read_error();
-    return Qnil;
-  }
-  
-  // Consume whatever was read
-  if (consume(&buf, buf.pos) < 0) {
-    handle_read_error();
-    return Qnil;
-  }
-  
-  return rb_ary_new3(3, name, INT2FIX(type), INT2FIX(seqid));
-}
-
-void Init_binaryprotocolaccelerated()
-{
-  m_thrift = rb_const_get(rb_cObject, rb_intern("Thrift"));
-  VALUE class_tbinproto = rb_const_get(m_thrift, rb_intern("BinaryProtocol"));
-  class_tbpa = rb_define_class_under(m_thrift, "BinaryProtocolAccelerated", class_tbinproto);
-  type_sym = ID2SYM(rb_intern("type"));
-  class_sym = ID2SYM(rb_intern("class"));
-  key_sym = ID2SYM(rb_intern("key"));
-  value_sym = ID2SYM(rb_intern("value"));
-  name_sym = ID2SYM(rb_intern("name"));
-  fields_id = rb_intern("FIELDS");
-  element_sym = ID2SYM(rb_intern("element"));
-  consume_bang_id = rb_intern("consume!");
-  string_buffer_id = rb_intern("string_buffer");
-  borrow_id = rb_intern("borrow");
-  keys_id = rb_intern("keys");
-  entries_id = rb_intern("entries");
-  rb_cSet = rb_const_get(rb_cObject, rb_intern("Set"));
-  
-  // For fast access
-  rb_define_method(class_tbpa, "encode_binary", tbpa_encode_binary, 1);
-  rb_define_method(class_tbpa, "decode_binary", tbpa_decode_binary, 2);
-  rb_define_method(class_tbpa, "read_message_begin", tbpa_read_message_begin, 0);
-  
-}
diff --git a/lib/rb/ext/constants.h b/lib/rb/ext/constants.h
new file mode 100644
index 0000000..f66a3ac
--- /dev/null
+++ b/lib/rb/ext/constants.h
@@ -0,0 +1,75 @@
+
+extern int TTYPE_STOP;
+extern int TTYPE_BOOL;
+extern int TTYPE_BYTE;
+extern int TTYPE_I16;
+extern int TTYPE_I32;
+extern int TTYPE_I64;
+extern int TTYPE_DOUBLE;
+extern int TTYPE_STRING;
+extern int TTYPE_MAP;
+extern int TTYPE_SET;
+extern int TTYPE_LIST;
+extern int TTYPE_STRUCT;
+
+extern ID validate_method_id;
+extern ID write_struct_begin_method_id;
+extern ID write_struct_end_method_id;
+extern ID write_field_begin_method_id;
+extern ID write_field_end_method_id;
+extern ID write_boolean_method_id;
+extern ID write_byte_method_id;
+extern ID write_i16_method_id;
+extern ID write_i32_method_id;
+extern ID write_i64_method_id;
+extern ID write_double_method_id;
+extern ID write_string_method_id;
+extern ID write_map_begin_method_id;
+extern ID write_map_end_method_id;
+extern ID write_list_begin_method_id;
+extern ID write_list_end_method_id;
+extern ID write_set_begin_method_id;
+extern ID write_set_end_method_id;
+extern ID size_method_id;
+extern ID read_bool_method_id;
+extern ID read_byte_method_id;
+extern ID read_i16_method_id;
+extern ID read_i32_method_id;
+extern ID read_i64_method_id;
+extern ID read_string_method_id;
+extern ID read_double_method_id;
+extern ID read_map_begin_method_id;
+extern ID read_map_end_method_id;
+extern ID read_list_begin_method_id;
+extern ID read_list_end_method_id;
+extern ID read_set_begin_method_id;
+extern ID read_set_end_method_id;
+extern ID read_struct_begin_method_id;
+extern ID read_struct_end_method_id;
+extern ID read_field_begin_method_id;
+extern ID read_field_end_method_id;
+extern ID keys_method_id;
+extern ID entries_method_id; 
+extern ID name_method_id; 
+extern ID sort_method_id;
+extern ID write_field_stop_method_id;
+extern ID skip_method_id;
+extern ID write_method_id;
+extern ID read_method_id;
+extern ID native_qmark_method_id;
+
+extern ID fields_const_id;
+extern ID transport_ivar_id;
+
+extern VALUE type_sym;
+extern VALUE name_sym;
+extern VALUE key_sym;
+extern VALUE value_sym;
+extern VALUE element_sym;
+extern VALUE class_sym;
+
+extern VALUE rb_cSet;
+extern VALUE thrift_module;
+extern VALUE thrift_types_module;
+extern VALUE class_thrift_protocol;
+extern VALUE protocol_exception_class;
\ No newline at end of file
diff --git a/lib/rb/ext/extconf.rb b/lib/rb/ext/extconf.rb
index 54ad5ed..6da2d7e 100644
--- a/lib/rb/ext/extconf.rb
+++ b/lib/rb/ext/extconf.rb
@@ -4,4 +4,4 @@
 
 have_func("strlcpy", "string.h")
 
-create_makefile 'binaryprotocolaccelerated'
+create_makefile 'thrift_native'
diff --git a/lib/rb/ext/memory_buffer.c b/lib/rb/ext/memory_buffer.c
new file mode 100644
index 0000000..a607ae2
--- /dev/null
+++ b/lib/rb/ext/memory_buffer.c
@@ -0,0 +1,52 @@
+#include <ruby.h>
+#include <constants.h>
+
+ID buf_ivar_id;
+ID index_ivar_id;
+
+ID slice_method_id;
+
+int GARBAGE_BUFFER_SIZE;
+
+#define GET_BUF(self) rb_ivar_get(self, buf_ivar_id)
+
+VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) {
+  VALUE buf = GET_BUF(self);
+  rb_str_buf_cat(buf, RSTRING(str)->ptr, RSTRING(str)->len);
+  return Qnil;
+}
+
+VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) {
+  int length = FIX2INT(length_value);
+  
+  VALUE index_value = rb_ivar_get(self, index_ivar_id);
+  int index = FIX2INT(index_value);
+  
+  VALUE buf = GET_BUF(self);
+  VALUE data = rb_funcall(buf, slice_method_id, 2, index_value, length_value);
+  
+  index += length;
+  if (index > RSTRING(buf)->len) {
+    index = RSTRING(buf)->len;
+  }
+  if (index >= GARBAGE_BUFFER_SIZE) {
+    rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(-1)));
+    index = 0;
+  }
+
+  rb_ivar_set(self, index_ivar_id, INT2FIX(index));
+  return data;
+}
+
+void Init_memory_buffer() {
+  VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBuffer"));
+  rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1);
+  rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1);
+  
+  buf_ivar_id = rb_intern("@buf");
+  index_ivar_id = rb_intern("@index");
+  
+  slice_method_id = rb_intern("slice");
+  
+  GARBAGE_BUFFER_SIZE = FIX2INT(rb_const_get(thrift_memory_buffer_class, rb_intern("GARBAGE_BUFFER_SIZE")));
+}
\ No newline at end of file
diff --git a/lib/rb/ext/memory_buffer.h b/lib/rb/ext/memory_buffer.h
new file mode 100644
index 0000000..ccc2aed
--- /dev/null
+++ b/lib/rb/ext/memory_buffer.h
@@ -0,0 +1,2 @@
+
+void Init_memory_buffer();
\ No newline at end of file
diff --git a/lib/rb/ext/protocol.c b/lib/rb/ext/protocol.c
new file mode 100644
index 0000000..b548f97
--- /dev/null
+++ b/lib/rb/ext/protocol.c
@@ -0,0 +1,166 @@
+#include <ruby.h>
+#include <protocol.h>
+#include <stdbool.h>
+#include <constants.h>
+#include <struct.h>
+
+static VALUE skip(VALUE self, int ttype) {
+  if (ttype == TTYPE_STOP) {
+    return Qnil;
+  } else if (ttype == TTYPE_BOOL) {
+    rb_funcall(self, read_bool_method_id, 0);
+  } else if (ttype == TTYPE_BYTE) {
+    rb_funcall(self, read_byte_method_id, 0);
+  } else if (ttype == TTYPE_I16) {
+    rb_funcall(self, read_i16_method_id, 0);
+  } else if (ttype == TTYPE_I32) {
+    rb_funcall(self, read_i32_method_id, 0);
+  } else if (ttype == TTYPE_I64) {
+    rb_funcall(self, read_i64_method_id, 0);
+  } else if (ttype == TTYPE_DOUBLE) {
+    rb_funcall(self, read_double_method_id, 0);
+  } else if (ttype == TTYPE_STRING) {
+    rb_funcall(self, read_string_method_id, 0);
+  } else if (ttype == TTYPE_STRUCT) {
+    rb_funcall(self, read_struct_begin_method_id, 0);
+    while (true) {
+      VALUE field_header = rb_funcall(self, read_field_begin_method_id, 0);
+      if (NIL_P(field_header) || FIX2INT(rb_ary_entry(field_header, 1)) == TTYPE_STOP ) {
+        break;
+      } 
+      skip(self, FIX2INT(rb_ary_entry(field_header, 1)));
+      rb_funcall(self, read_field_end_method_id, 0);
+    }
+    rb_funcall(self, read_struct_end_method_id, 0);
+  } else if (ttype == TTYPE_MAP) {
+    int i;
+    VALUE map_header = rb_funcall(self, read_map_begin_method_id, 0);
+    int ktype = FIX2INT(rb_ary_entry(map_header, 0));
+    int vtype = FIX2INT(rb_ary_entry(map_header, 1));
+    int size = FIX2INT(rb_ary_entry(map_header, 2));
+    
+    for (i = 0; i < size; i++) {
+      skip(self, ktype);
+      skip(self, vtype);
+    }
+    rb_funcall(self, read_map_end_method_id, 0);
+  } else if (ttype == TTYPE_LIST || ttype == TTYPE_SET) {
+    int i;
+    VALUE collection_header = rb_funcall(self, ttype == TTYPE_LIST ? read_list_begin_method_id : read_set_begin_method_id, 0);
+    int etype = FIX2INT(rb_ary_entry(collection_header, 0));
+    int size = FIX2INT(rb_ary_entry(collection_header, 1));
+    for (i = 0; i < size; i++) {
+      skip(self, etype);
+    }
+    rb_funcall(self, ttype == TTYPE_LIST ? read_list_end_method_id : read_set_end_method_id, 0);
+  } else {
+    rb_raise(rb_eNotImpError, "don't know how to skip type %d", ttype);
+  }
+
+  return Qnil;
+}
+
+VALUE rb_thrift_protocol_native_qmark(VALUE self) {
+  return Qfalse;
+}
+
+VALUE rb_thrift_protocol_skip(VALUE protocol, VALUE ttype) {
+  return skip(protocol, FIX2INT(ttype));
+}
+
+VALUE rb_thrift_write_message_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_struct_begin(VALUE self, VALUE name) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_struct_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_field_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_map_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_list_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_write_set_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thrift_read_message_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_struct_begin(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_struct_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_field_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_map_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_list_end(VALUE self) {
+  return Qnil;
+}
+
+VALUE rb_thift_read_set_end(VALUE self) {
+  return Qnil;
+}
+
+void Init_protocol() {
+  VALUE c_protocol = rb_const_get(thrift_module, rb_intern("Protocol"));
+  
+  rb_define_method(c_protocol, "skip", rb_thrift_protocol_skip, 1);
+  rb_define_method(c_protocol, "write_message_end", rb_thrift_write_message_end, 0);
+  rb_define_method(c_protocol, "write_struct_begin", rb_thrift_write_struct_begin, 1);
+  rb_define_method(c_protocol, "write_struct_end", rb_thrift_write_struct_end, 0);
+  rb_define_method(c_protocol, "write_field_end", rb_thrift_write_field_end, 0);
+  rb_define_method(c_protocol, "write_map_end", rb_thrift_write_map_end, 0);
+  rb_define_method(c_protocol, "write_list_end", rb_thrift_write_list_end, 0);
+  rb_define_method(c_protocol, "write_set_end", rb_thrift_write_set_end, 0);
+  rb_define_method(c_protocol, "read_message_end", rb_thrift_read_message_end, 0);
+  rb_define_method(c_protocol, "read_struct_begin", rb_thift_read_struct_begin, 0);
+  rb_define_method(c_protocol, "read_struct_end", rb_thift_read_struct_end, 0);
+  rb_define_method(c_protocol, "read_field_end", rb_thift_read_field_end, 0);
+  rb_define_method(c_protocol, "read_map_end", rb_thift_read_map_end, 0);
+  rb_define_method(c_protocol, "read_list_end", rb_thift_read_list_end, 0);
+  rb_define_method(c_protocol, "read_set_end", rb_thift_read_set_end, 0);
+  rb_define_method(c_protocol, "native?", rb_thrift_protocol_native_qmark, 0);
+  
+  // native_proto_method_table *npmt;
+  // npmt = ALLOC(native_proto_method_table);
+  // npmt->write_message_end = rb_thrift_write_message_end;
+  // npmt->write_struct_begin = rb_thrift_write_struct_begin;
+  // npmt->write_struct_end = rb_thrift_write_struct_end;
+  // npmt->write_field_end = rb_thrift_write_field_end;
+  // npmt->write_map_end = rb_thrift_write_map_end;
+  // npmt->write_list_end = rb_thrift_write_list_end;
+  // npmt->write_set_end = rb_thrift_write_set_end;
+  // npmt->read_message_end = rb_thrift_read_message_end;
+  // npmt->read_struct_begin = rb_thift_read_struct_begin;
+  // npmt->read_struct_end = rb_thift_read_struct_end;
+  // npmt->read_field_end = rb_thift_read_field_end;
+  // npmt->read_map_end = rb_thift_read_map_end;
+  // npmt->read_list_end = rb_thift_read_list_end;
+  // npmt->read_set_end = rb_thift_read_set_end;
+  // 
+  // VALUE method_table_object = Data_Wrap_Struct(rb_cObject, 0, free, npmt);
+  // rb_const_set(c_protocol, rb_intern("@native_method_table"), method_table_object);
+}
\ No newline at end of file
diff --git a/lib/rb/ext/protocol.h b/lib/rb/ext/protocol.h
new file mode 100644
index 0000000..534c859
--- /dev/null
+++ b/lib/rb/ext/protocol.h
@@ -0,0 +1,2 @@
+
+void Init_protocol();
\ No newline at end of file
diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c
new file mode 100644
index 0000000..0e7aa1a
--- /dev/null
+++ b/lib/rb/ext/struct.c
@@ -0,0 +1,553 @@
+
+#include <struct.h>
+#include <constants.h>
+
+static native_proto_method_table *mt;
+
+#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)
+
+//-------------------------------------------
+// Writing section
+//-------------------------------------------
+
+// default fn pointers for protocol stuff here
+
+VALUE default_write_bool(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_boolean_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_byte(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_byte_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_i16(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_i16_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_i32(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_i32_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_i64(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_i64_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_double(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_double_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_string(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_string_method_id, 1, value);
+  return Qnil;
+}
+
+VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
+  rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
+  return Qnil;
+}
+
+VALUE default_write_list_end(VALUE protocol) {
+  rb_funcall(protocol, write_list_end_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
+  rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
+  return Qnil;
+}
+
+VALUE default_write_set_end(VALUE protocol) {
+  rb_funcall(protocol, write_set_end_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
+  rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
+  return Qnil;
+}
+
+VALUE default_write_map_end(VALUE protocol) {
+  rb_funcall(protocol, write_map_end_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
+  rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
+  return Qnil;
+}
+
+VALUE default_write_struct_end(VALUE protocol) {
+  rb_funcall(protocol, write_struct_end_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
+  rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
+  return Qnil;
+}
+
+VALUE default_write_field_end(VALUE protocol) {
+  rb_funcall(protocol, write_field_end_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_write_field_stop(VALUE protocol) {
+  rb_funcall(protocol, write_field_stop_method_id, 0);
+  return Qnil;
+}
+
+VALUE default_read_field_begin(VALUE protocol) {
+  return rb_funcall(protocol, read_field_begin_method_id, 0);
+}
+
+VALUE default_read_field_end(VALUE protocol) {
+  return rb_funcall(protocol, read_field_end_method_id, 0);
+}
+
+VALUE default_read_map_begin(VALUE protocol) {
+  return rb_funcall(protocol, read_map_begin_method_id, 0);
+}
+
+VALUE default_read_map_end(VALUE protocol) {
+  return rb_funcall(protocol, read_map_end_method_id, 0);
+}
+
+VALUE default_read_list_begin(VALUE protocol) {
+  return rb_funcall(protocol, read_list_begin_method_id, 0);
+}
+
+VALUE default_read_list_end(VALUE protocol) {
+  return rb_funcall(protocol, read_list_end_method_id, 0);
+}
+
+VALUE default_read_set_begin(VALUE protocol) {
+  return rb_funcall(protocol, read_set_begin_method_id, 0);
+}
+
+VALUE default_read_set_end(VALUE protocol) {
+  return rb_funcall(protocol, read_set_end_method_id, 0);
+}
+
+VALUE default_read_byte(VALUE protocol) {
+  return rb_funcall(protocol, read_byte_method_id, 0);
+}
+
+VALUE default_read_bool(VALUE protocol) {
+  return rb_funcall(protocol, read_bool_method_id, 0);
+}
+
+VALUE default_read_i16(VALUE protocol) {
+  return rb_funcall(protocol, read_i16_method_id, 0);
+}
+
+VALUE default_read_i32(VALUE protocol) {
+  return rb_funcall(protocol, read_i32_method_id, 0);
+}
+
+VALUE default_read_i64(VALUE protocol) {
+  return rb_funcall(protocol, read_i64_method_id, 0);
+}
+
+VALUE default_read_double(VALUE protocol) {
+  return rb_funcall(protocol, read_double_method_id, 0);
+}
+
+VALUE default_read_string(VALUE protocol) {
+  return rb_funcall(protocol, read_string_method_id, 0);
+}
+
+VALUE default_read_struct_begin(VALUE protocol) {
+  return rb_funcall(protocol, read_struct_begin_method_id, 0);
+}
+
+VALUE default_read_struct_end(VALUE protocol) {
+  return rb_funcall(protocol, read_struct_end_method_id, 0);
+}
+
+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;
+
+  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;
+  
+}
+
+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);
+}
+
+// end default protocol methods
+
+
+static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
+static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
+
+VALUE get_field_value(VALUE obj, VALUE field_name) {
+  char name_buf[RSTRING(field_name)->len + 1];
+  
+  name_buf[0] = '@';
+  strlcpy(&name_buf[1], RSTRING(field_name)->ptr, sizeof(name_buf));
+
+  VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
+  
+  return value;
+}
+
+static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
+  int sz, i;
+  
+  if (ttype == TTYPE_MAP) {
+    VALUE keys;
+    VALUE key;
+    VALUE val;
+
+    Check_Type(value, T_HASH);
+    
+    VALUE key_info = rb_hash_aref(field_info, key_sym);
+    VALUE keytype_value = rb_hash_aref(key_info, type_sym);
+    int keytype = FIX2INT(keytype_value);
+    
+    VALUE value_info = rb_hash_aref(field_info, value_sym);
+    VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
+    int valuetype = FIX2INT(valuetype_value);
+    
+    keys = rb_funcall(value, keys_method_id, 0);
+    
+    sz = RARRAY(keys)->len;
+    
+    mt->write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
+    
+    for (i = 0; i < sz; i++) {
+      key = rb_ary_entry(keys, i);
+      val = rb_hash_aref(value, key);
+      
+      if (IS_CONTAINER(keytype)) {
+        write_container(keytype, key_info, key, protocol);
+      } else {
+        write_anything(keytype, key, protocol, key_info);
+      }
+      
+      if (IS_CONTAINER(valuetype)) {
+        write_container(valuetype, value_info, val, protocol);
+      } else {
+        write_anything(valuetype, val, protocol, value_info);
+      }
+    }
+    
+    mt->write_map_end(protocol);
+  } else if (ttype == TTYPE_LIST) {
+    Check_Type(value, T_ARRAY);
+
+    sz = RARRAY(value)->len;
+
+    VALUE element_type_info = rb_hash_aref(field_info, element_sym);
+    VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
+    int element_type = FIX2INT(element_type_value);
+    
+    mt->write_list_begin(protocol, element_type_value, INT2FIX(sz));
+    for (i = 0; i < sz; ++i) {
+      VALUE val = rb_ary_entry(value, i);
+      if (IS_CONTAINER(element_type)) {
+        write_container(element_type, element_type_info, val, protocol);
+      } else {
+        write_anything(element_type, val, protocol, element_type_info);
+      }
+    }
+    mt->write_list_end(protocol);
+  } else if (ttype == TTYPE_SET) {
+    VALUE items;
+
+    if (TYPE(value) == T_ARRAY) {
+      items = value;
+    } else {        
+      if (rb_cSet == CLASS_OF(value)) {
+        items = rb_funcall(value, entries_method_id, 0);
+      } else {
+        Check_Type(value, T_HASH);
+        items = rb_funcall(value, keys_method_id, 0);
+      }
+    }
+
+    sz = RARRAY(items)->len;
+
+    VALUE element_type_info = rb_hash_aref(field_info, element_sym);
+    VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
+    int element_type = FIX2INT(element_type_value);
+    
+    mt->write_set_begin(protocol, element_type_value, INT2FIX(sz));
+    
+    for (i = 0; i < sz; i++) {
+      VALUE val = rb_ary_entry(items, i);
+      if (IS_CONTAINER(element_type)) {
+        write_container(element_type, element_type_info, val, protocol);
+      } else {
+        write_anything(element_type, val, protocol, element_type_info);
+      }
+    }
+    
+    mt->write_set_end(protocol);
+  } else {
+    rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
+  }
+}
+
+static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
+  if (ttype == TTYPE_BOOL) {
+    mt->write_bool(protocol, value);
+  } else if (ttype == TTYPE_BYTE) {
+    mt->write_byte(protocol, value);
+  } else if (ttype == TTYPE_I16) {
+    mt->write_i16(protocol, value);
+  } else if (ttype == TTYPE_I32) {
+    mt->write_i32(protocol, value);
+  } else if (ttype == TTYPE_I64) {
+    mt->write_i64(protocol, value);
+  } else if (ttype == TTYPE_DOUBLE) {
+    mt->write_double(protocol, value);
+  } else if (ttype == TTYPE_STRING) {
+    mt->write_string(protocol, value);
+  } else if (IS_CONTAINER(ttype)) {
+    write_container(ttype, field_info, value, protocol);
+  } else if (ttype == TTYPE_STRUCT) {
+    rb_thrift_struct_write(value, protocol);
+  } else {
+    rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
+  }
+}
+
+static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
+  // 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();
+  }
+  
+  // write struct begin
+  mt->write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
+  
+  // iterate through all the fields here
+  VALUE struct_fields = STRUCT_FIELDS(self);
+  VALUE struct_field_ids_unordered = rb_funcall(struct_fields, keys_method_id, 0);
+  VALUE struct_field_ids_ordered = rb_funcall(struct_field_ids_unordered, sort_method_id, 0);
+  
+  int i = 0;
+  for (i=0; i < RARRAY(struct_field_ids_ordered)->len; i++) {
+    VALUE field_id = rb_ary_entry(struct_field_ids_ordered, i);
+    VALUE field_info = rb_hash_aref(struct_fields, field_id);
+
+    VALUE ttype_value = rb_hash_aref(field_info, type_sym);
+    int ttype = FIX2INT(ttype_value);
+    VALUE field_name = rb_hash_aref(field_info, name_sym);
+    VALUE field_value = get_field_value(self, field_name);
+
+    if (!NIL_P(field_value)) {
+      mt->write_field_begin(protocol, field_name, ttype_value, field_id);
+      
+      write_anything(ttype, field_value, protocol, field_info);
+      
+      mt->write_field_end(protocol);
+    }
+  }
+  
+  mt->write_field_stop(protocol);
+  
+  // write struct end
+  mt->write_struct_end(protocol);
+  
+  return Qnil;
+}
+
+//-------------------------------------------
+// Reading section
+//-------------------------------------------
+
+static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
+
+static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
+  char name_buf[RSTRING(field_name)->len + 1];
+
+  name_buf[0] = '@';
+  strlcpy(&name_buf[1], RSTRING(field_name)->ptr, sizeof(name_buf));
+
+  rb_ivar_set(obj, rb_intern(name_buf), value);
+}
+
+static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
+  VALUE result = Qnil;
+  
+  if (ttype == TTYPE_BOOL) {
+    result = mt->read_bool(protocol);
+  } else if (ttype == TTYPE_BYTE) {
+    result = mt->read_byte(protocol);
+  } else if (ttype == TTYPE_I16) {
+    result = mt->read_i16(protocol);
+  } else if (ttype == TTYPE_I32) {
+    result = mt->read_i32(protocol);
+  } else if (ttype == TTYPE_I64) {
+    result = mt->read_i64(protocol);
+  } else if (ttype == TTYPE_STRING) {
+    result = mt->read_string(protocol);
+  } else if (ttype == TTYPE_DOUBLE) {
+    result = mt->read_double(protocol);
+  } else if (ttype == TTYPE_STRUCT) {
+    VALUE klass = rb_hash_aref(field_info, class_sym);
+    result = rb_class_new_instance(0, NULL, klass);
+    rb_thrift_struct_read(result, protocol);
+  } else if (ttype == TTYPE_MAP) {
+    int i;
+
+    VALUE map_header = mt->read_map_begin(protocol);
+    int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
+    int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
+    int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
+    
+    VALUE key_info = rb_hash_aref(field_info, key_sym);
+    VALUE value_info = rb_hash_aref(field_info, value_sym);
+
+    result = rb_hash_new();
+    
+    for (i = 0; i < num_entries; ++i) {
+      VALUE key, val;
+      
+      key = read_anything(protocol, key_ttype, key_info);
+      val = read_anything(protocol, value_ttype, value_info);
+      
+      rb_hash_aset(result, key, val);
+    }
+    
+    mt->read_map_end(protocol);
+  } else if (ttype == TTYPE_LIST) {
+    int i;
+
+    VALUE list_header = mt->read_list_begin(protocol);
+    int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
+    int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
+    result = rb_ary_new2(num_elements);
+    
+    for (i = 0; i < num_elements; ++i) {
+      rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
+    }
+
+
+    mt->read_list_end(protocol);
+  } else if (ttype == TTYPE_SET) {
+    VALUE items;
+    int i;
+
+    VALUE set_header = mt->read_set_begin(protocol);
+    int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
+    int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
+    items = rb_ary_new2(num_elements);
+    
+    for (i = 0; i < num_elements; ++i) {
+      rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
+    }
+    
+
+    mt->read_set_end(protocol);
+    
+    result = rb_class_new_instance(1, &items, rb_cSet);
+  } else {
+    rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
+  }
+  
+  return result;
+}
+
+static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
+  // read struct begin
+  mt->read_struct_begin(protocol);
+
+  VALUE struct_fields = STRUCT_FIELDS(self);
+  
+  // read each field
+  while (true) {
+    VALUE field_header = rb_funcall(protocol, read_field_begin_method_id, 0);
+    VALUE field_type_value = rb_ary_entry(field_header, 1);
+    int field_type = FIX2INT(field_type_value);
+    
+    if (field_type == TTYPE_STOP) {
+      break;
+    }
+
+    // make sure we got a type we expected
+    VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
+
+    if (!NIL_P(field_info)) {
+      int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
+      if (field_type == specified_type) {
+        // read the value
+        VALUE name = rb_hash_aref(field_info, name_sym);
+        set_field_value(self, name, read_anything(protocol, field_type, field_info));
+      } else {
+        rb_funcall(protocol, skip_method_id, 1, field_type_value);
+      }
+    } else {
+      rb_funcall(protocol, skip_method_id, 1, field_type_value);
+    }
+    
+    // read field end
+    mt->read_field_end(protocol);
+  }
+  
+  // read struct end
+  mt->read_struct_end(protocol);
+  
+  return Qnil;
+}
+
+void Init_struct() {
+  VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
+  
+  rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
+  rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
+  
+  set_default_proto_function_pointers();
+}
+
diff --git a/lib/rb/ext/struct.h b/lib/rb/ext/struct.h
new file mode 100644
index 0000000..bf2350d
--- /dev/null
+++ b/lib/rb/ext/struct.h
@@ -0,0 +1,48 @@
+#include <stdbool.h>
+#include <ruby.h>
+
+typedef struct native_proto_method_table {
+  VALUE (*write_bool)(VALUE, VALUE);
+  VALUE (*write_byte)(VALUE, VALUE);
+  VALUE (*write_i16)(VALUE, VALUE);
+  VALUE (*write_i32)(VALUE, VALUE);
+  VALUE (*write_i64)(VALUE, VALUE);
+  VALUE (*write_double)(VALUE, VALUE);
+  VALUE (*write_string)(VALUE, VALUE);
+  VALUE (*write_list_begin)(VALUE, VALUE, VALUE);
+  VALUE (*write_list_end)(VALUE);
+  VALUE (*write_set_begin)(VALUE, VALUE, VALUE);
+  VALUE (*write_set_end)(VALUE);
+  VALUE (*write_map_begin)(VALUE, VALUE, VALUE, VALUE);
+  VALUE (*write_map_end)(VALUE);
+  VALUE (*write_struct_begin)(VALUE, VALUE);
+  VALUE (*write_struct_end)(VALUE);
+  VALUE (*write_field_begin)(VALUE, VALUE, VALUE, VALUE);
+  VALUE (*write_field_end)(VALUE);
+  VALUE (*write_field_stop)(VALUE);
+  VALUE (*write_message_begin)(VALUE, VALUE, VALUE, VALUE);
+  VALUE (*write_message_end)(VALUE);
+  
+  VALUE (*read_message_begin)(VALUE);
+  VALUE (*read_message_end)(VALUE);
+  VALUE (*read_field_begin)(VALUE);
+  VALUE (*read_field_end)(VALUE);
+  VALUE (*read_map_begin)(VALUE);
+  VALUE (*read_map_end)(VALUE);
+  VALUE (*read_list_begin)(VALUE);
+  VALUE (*read_list_end)(VALUE);
+  VALUE (*read_set_begin)(VALUE);
+  VALUE (*read_set_end)(VALUE);
+  VALUE (*read_byte)(VALUE);
+  VALUE (*read_bool)(VALUE);
+  VALUE (*read_i16)(VALUE);
+  VALUE (*read_i32)(VALUE);
+  VALUE (*read_i64)(VALUE);
+  VALUE (*read_double)(VALUE);
+  VALUE (*read_string)(VALUE);
+  VALUE (*read_struct_begin)(VALUE);
+  VALUE (*read_struct_end)(VALUE);
+  
+} native_proto_method_table;
+
+void Init_struct();
\ No newline at end of file
diff --git a/lib/rb/ext/thrift_native.c b/lib/rb/ext/thrift_native.c
new file mode 100644
index 0000000..60d0fc0
--- /dev/null
+++ b/lib/rb/ext/thrift_native.c
@@ -0,0 +1,169 @@
+#include <ruby.h>
+#include <struct.h>
+#include <binary_protocol_accelerated.h>
+#include <protocol.h>
+#include <memory_buffer.h>
+
+// cached classes/modules
+VALUE rb_cSet;
+VALUE thrift_module;
+VALUE thrift_types_module;
+
+// TType constants
+int TTYPE_STOP;
+int TTYPE_BOOL;
+int TTYPE_BYTE;
+int TTYPE_I16;
+int TTYPE_I32;
+int TTYPE_I64;
+int TTYPE_DOUBLE;
+int TTYPE_STRING;
+int TTYPE_MAP;
+int TTYPE_SET;
+int TTYPE_LIST;
+int TTYPE_STRUCT;
+
+// method ids
+ID validate_method_id;
+ID write_struct_begin_method_id;
+ID write_struct_end_method_id;
+ID write_field_begin_method_id;
+ID write_field_end_method_id;
+ID write_boolean_method_id;
+ID write_byte_method_id;
+ID write_i16_method_id;
+ID write_i32_method_id;
+ID write_i64_method_id;
+ID write_double_method_id;
+ID write_string_method_id;
+ID write_map_begin_method_id;
+ID write_map_end_method_id;
+ID write_list_begin_method_id;
+ID write_list_end_method_id;
+ID write_set_begin_method_id;
+ID write_set_end_method_id;
+ID size_method_id;
+ID read_bool_method_id;
+ID read_byte_method_id;
+ID read_i16_method_id;
+ID read_i32_method_id;
+ID read_i64_method_id;
+ID read_string_method_id;
+ID read_double_method_id;
+ID read_map_begin_method_id;
+ID read_map_end_method_id;
+ID read_list_begin_method_id;
+ID read_list_end_method_id;
+ID read_set_begin_method_id;
+ID read_set_end_method_id;
+ID read_struct_begin_method_id;
+ID read_struct_end_method_id;
+ID read_field_begin_method_id;
+ID read_field_end_method_id;
+ID keys_method_id;
+ID entries_method_id; 
+ID name_method_id; 
+ID sort_method_id;
+ID write_field_stop_method_id;
+ID skip_method_id;
+ID write_method_id;
+ID read_method_id;
+ID native_qmark_method_id;
+
+// constant ids
+ID fields_const_id;
+ID transport_ivar_id;
+
+// cached symbols
+VALUE type_sym;
+VALUE name_sym;
+VALUE key_sym;
+VALUE value_sym;
+VALUE element_sym;
+VALUE class_sym;
+VALUE protocol_exception_class;
+
+void Init_thrift_native() {
+  // cached classes
+  thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift"));
+  thrift_types_module = rb_const_get(thrift_module, rb_intern("Types"));
+  rb_cSet = rb_const_get(rb_cObject, rb_intern("Set"));
+  protocol_exception_class = rb_const_get(thrift_module, rb_intern("ProtocolException"));
+  
+  // Init ttype constants
+  TTYPE_BOOL = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BOOL")));
+  TTYPE_BYTE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BYTE")));
+  TTYPE_I16 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I16")));
+  TTYPE_I32 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I32")));
+  TTYPE_I64 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I64")));
+  TTYPE_DOUBLE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("DOUBLE")));
+  TTYPE_STRING = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRING")));
+  TTYPE_MAP = FIX2INT(rb_const_get(thrift_types_module, rb_intern("MAP")));
+  TTYPE_SET = FIX2INT(rb_const_get(thrift_types_module, rb_intern("SET")));
+  TTYPE_LIST = FIX2INT(rb_const_get(thrift_types_module, rb_intern("LIST")));
+  TTYPE_STRUCT = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRUCT")));
+
+  // method ids
+  validate_method_id = rb_intern("validate");
+  write_struct_begin_method_id = rb_intern("write_struct_begin");
+  write_struct_end_method_id = rb_intern("write_struct_end");
+  write_field_begin_method_id = rb_intern("write_field_begin");
+  write_field_end_method_id = rb_intern("write_field_end");
+  write_boolean_method_id = rb_intern("write_bool");
+  write_byte_method_id = rb_intern("write_byte");
+  write_i16_method_id = rb_intern("write_i16");
+  write_i32_method_id = rb_intern("write_i32");
+  write_i64_method_id = rb_intern("write_i64");
+  write_double_method_id = rb_intern("write_double");
+  write_string_method_id = rb_intern("write_string");
+  write_map_begin_method_id = rb_intern("write_map_begin");
+  write_map_end_method_id = rb_intern("write_map_end");
+  write_list_begin_method_id = rb_intern("write_list_begin");
+  write_list_end_method_id = rb_intern("write_list_end");
+  write_set_begin_method_id = rb_intern("write_set_begin");
+  write_set_end_method_id = rb_intern("write_set_end");
+  size_method_id = rb_intern("size");
+  read_bool_method_id = rb_intern("read_bool");
+  read_byte_method_id = rb_intern("read_byte");
+  read_i16_method_id = rb_intern("read_i16");
+  read_i32_method_id = rb_intern("read_i32");
+  read_i64_method_id = rb_intern("read_i64");
+  read_string_method_id = rb_intern("read_string");
+  read_double_method_id = rb_intern("read_double");
+  read_map_begin_method_id = rb_intern("read_map_begin");
+  read_map_end_method_id = rb_intern("read_map_end");  
+  read_list_begin_method_id = rb_intern("read_list_begin");
+  read_list_end_method_id = rb_intern("read_list_end");
+  read_set_begin_method_id = rb_intern("read_set_begin");
+  read_set_end_method_id = rb_intern("read_set_end");
+  read_struct_begin_method_id = rb_intern("read_struct_begin");
+  read_struct_end_method_id = rb_intern("read_struct_end");
+  read_field_begin_method_id = rb_intern("read_field_begin");
+  read_field_end_method_id = rb_intern("read_field_end");
+  keys_method_id = rb_intern("keys");
+  entries_method_id = rb_intern("entries");
+  name_method_id = rb_intern("name");
+  sort_method_id = rb_intern("sort");
+  write_field_stop_method_id = rb_intern("write_field_stop");
+  skip_method_id = rb_intern("skip");
+  write_method_id = rb_intern("write");
+  read_method_id = rb_intern("read");
+  native_qmark_method_id = rb_intern("native?");
+  
+  // constant ids
+  fields_const_id = rb_intern("FIELDS");
+  transport_ivar_id = rb_intern("@trans");
+  
+  // cached symbols
+  type_sym = ID2SYM(rb_intern("type"));
+  name_sym = ID2SYM(rb_intern("name"));
+  key_sym = ID2SYM(rb_intern("key"));
+  value_sym = ID2SYM(rb_intern("value"));
+  element_sym = ID2SYM(rb_intern("element"));
+  class_sym = ID2SYM(rb_intern("class"));
+
+  Init_protocol();
+  Init_struct();
+  Init_binary_protocol_accelerated();
+  Init_memory_buffer();
+}
\ No newline at end of file