Rev 2 of Thrift, the Pillar successor

Summary: End-to-end communications and serialization in C++ is working

Reviewed By: aditya

Test Plan: See the new top-level test/ folder. It vaguely resembles a unit test, though it could be more automated.

Revert Plan: Revertible

Notes: Still a LOT of optimization work to be done on the generated C++ code, which should be using dynamic memory in a number of places. Next major task is writing the PHP/Java/Python generators.




git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664712 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/Makefile b/compiler/Makefile
index 8fa9e60..62ce275 100644
--- a/compiler/Makefile
+++ b/compiler/Makefile
@@ -43,14 +43,17 @@
             lex.yy.cc
 
 # Object files
-OBJ_FILES = thrift.tab.o \
-            lex.yy.o \
-            ${SRC_FILES:.cc=.o}
+OBJ_FILES = ${SRC_FILES:.cc=.o}
+
+# Generated object files
+GOB_FILES = thrift.tab.o \
+            lex.yy.o
 
 # Apply directory prefixes
 SRCS = ${addprefix $(SRC_DIR), $(SRC_FILES)}
 GENS = ${addprefix $(GEN_DIR), $(GEN_FILES)}
 OBJS = ${addprefix $(OBJ_DIR), $(OBJ_FILES)}
+GOBS = ${addprefix $(OBJ_DIR), $(GOB_FILES)}
 
 # Compile with strict warnings
 CFL = -g -Wall -I$(SRC_DIR) -I$(OBJ_DIR)
@@ -60,7 +63,7 @@
 
 # Scanner generation
 $(GEN_DIR)lex.yy.cc: $(SRC_DIR)thrift.l
-	$(LEX) -o$(GEN_DIR)lex.yy.cc $(SRC_DIR)thrift.l
+	$(LEX) -o$@ $(SRC_DIR)thrift.l
 
 # Parser generation
 $(GEN_DIR)thrift.tab.hh: $(GEN_DIR)thrift.tab.cc
@@ -69,68 +72,36 @@
 	$(YACC) -d -o$(GEN_DIR)thrift.tab.cc $(SRC_DIR)thrift.y
 
 # C++ compilation
-$(OBJS): $(GEN_DIR)thrift.tab.cc $(GEN_DIR)lex.yy.cc obj_dir
+$(OBJ_DIR)lex.yy.o: $(GEN_DIR)lex.yy.cc
+	$(CC) $(CFL) -c -o $@ $(GEN_DIR)lex.yy.cc
+
+# C++ compilation
+$(OBJ_DIR)thrift.tab.o: $(GEN_DIR)thrift.tab.cc
+	$(CC) $(CFL) -c -o $@ $(GEN_DIR)thrift.tab.cc
+
+# C++ compilation
+$(OBJS): $(SRCS)
 	$(CC) $(CFL) -c -o $@ ${subst $(OBJ_DIR),$(SRC_DIR),$*.cc}
 
-# Header dependency
-$(SRC_DIR)main.cc: $(SRC_DIR)*.h
-
 # Main build rule
-thrift:	$(OBJS)	
-	$(LD) $(CFL) -o $(BIN_DIR)thrift $(OBJS) $(LIBS)
+thrift:	$(OBJS)	$(GOBS)
+	$(LD) $(CFL) -o $(BIN_DIR)thrift $(OBJS) $(GOBS) $(LIBS)
 
 # Build directory
-obj_dir:	
+obj_dirs:	
 	$(MKDIR) -p $(OBJ_DIR)parse
 	$(MKDIR) -p $(OBJ_DIR)generate
 
-# This will auto-make dependency rules
-depend:
-	makedepend -- $(CFL) -- $(SRCS)
+# Install it
+install: thrift
+	sudo install bin/thrift /usr/local/bin/thrift
 
 # Remove auto-gen'd files and binaries
 clean:
 	rm -f \
 	$(OBJS) \
+	$(GOBS) \
 	$(GENS) \
 	$(BIN_DIR)thrift.exe \
 	$(BIN_DIR)thrift
-# DO NOT DELETE
 
-src/main.o: /usr/include/stdlib.h /usr/include/features.h
-src/main.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
-src/main.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs-64.h
-src/main.o: /usr/include/stdio.h /usr/include/bits/types.h
-src/main.o: /usr/include/bits/typesizes.h /usr/include/libio.h
-src/main.o: /usr/include/_G_config.h /usr/include/wchar.h
-src/main.o: /usr/include/bits/wchar.h /usr/include/gconv.h
-src/main.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-src/main.o: src/globals.h src/main.h src/parse/t_program.h
-src/main.o: src/parse/t_base_type.h src/parse/t_type.h src/parse/t_typedef.h
-src/main.o: src/parse/t_enum.h src/parse/t_constant.h src/parse/t_struct.h
-src/main.o: src/parse/t_list.h src/parse/t_field.h src/parse/t_service.h
-src/main.o: src/parse/t_function.h src/generate/t_cpp_generator.h
-src/main.o: src/generate/t_generator.h
-src/generate/t_generator.o: src/generate/t_generator.h src/parse/t_program.h
-src/generate/t_generator.o: src/parse/t_base_type.h src/parse/t_type.h
-src/generate/t_generator.o: src/parse/t_typedef.h src/parse/t_enum.h
-src/generate/t_generator.o: src/parse/t_constant.h src/parse/t_struct.h
-src/generate/t_generator.o: src/parse/t_list.h src/parse/t_field.h
-src/generate/t_generator.o: src/parse/t_service.h src/parse/t_function.h
-src/generate/t_cpp_generator.o: /usr/include/sys/stat.h
-src/generate/t_cpp_generator.o: /usr/include/features.h
-src/generate/t_cpp_generator.o: /usr/include/sys/cdefs.h
-src/generate/t_cpp_generator.o: /usr/include/gnu/stubs.h
-src/generate/t_cpp_generator.o: /usr/include/bits/wordsize.h
-src/generate/t_cpp_generator.o: /usr/include/gnu/stubs-64.h
-src/generate/t_cpp_generator.o: /usr/include/bits/types.h
-src/generate/t_cpp_generator.o: /usr/include/bits/typesizes.h
-src/generate/t_cpp_generator.o: /usr/include/bits/stat.h
-src/generate/t_cpp_generator.o: src/generate/t_cpp_generator.h
-src/generate/t_cpp_generator.o: src/generate/t_generator.h
-src/generate/t_cpp_generator.o: src/parse/t_program.h src/parse/t_base_type.h
-src/generate/t_cpp_generator.o: src/parse/t_type.h src/parse/t_typedef.h
-src/generate/t_cpp_generator.o: src/parse/t_enum.h src/parse/t_constant.h
-src/generate/t_cpp_generator.o: src/parse/t_struct.h src/parse/t_list.h
-src/generate/t_cpp_generator.o: src/parse/t_field.h src/parse/t_service.h
-src/generate/t_cpp_generator.o: src/parse/t_function.h src/globals.h
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
index b328a1a..e47c13b 100644
--- a/compiler/src/generate/t_cpp_generator.cc
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -1,4 +1,6 @@
+#include <stdlib.h>
 #include <sys/stat.h>
+#include <sstream>
 #include "t_cpp_generator.h"
 #include "globals.h"
 using namespace std;
@@ -14,7 +16,7 @@
   mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
 
   // Make output file
-  string f_types_name = string(T_CPP_DIR)+"/"+tprogram->get_name()+"_types.h";
+  string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"Types.h";
   f_types_.open(f_types_name.c_str());
 
   // Print header
@@ -23,13 +25,13 @@
 
   // Start ifndef
   f_types_ <<
-    "#ifndef thrift_" << tprogram->get_name() << "_types_h" << endl <<
-    "#define thrift_" << tprogram->get_name() << "_types_h" << endl <<
+    "#ifndef " << program_name_ << "_TYPES_H" << endl <<
+    "#define " << program_name_ << "_TYPES_H" << endl <<
     endl;
   
   // Include base types
   f_types_ <<
-    "#include <sys/types.h>" << endl <<
+    "#include \"Thrift.h\"" << endl <<
     endl;
 }
 
@@ -109,13 +111,11 @@
   
   indent_up();
 
-  const t_list* memberlist = tstruct->get_members();
-  vector<t_field*> members = memberlist->elems();
-  vector<t_field*>::iterator m_iter; 
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter; 
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    f_types_ <<
-      indent() << (*m_iter)->get_type()->get_name() << " " <<
-      (*m_iter)->get_name() << ";" << endl;
+    indent(f_types_) <<
+      declare_field(*m_iter) << endl;
   }
   
   indent_down();
@@ -135,24 +135,24 @@
  */
 void t_cpp_generator::generate_service(t_service* tservice) {
   // Make output files
-  string f_header_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".h";
+  string f_header_name = string(T_CPP_DIR)+"/"+service_name_+".h";
   f_header_.open(f_header_name.c_str());
-  string f_service_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".cc";
+  string f_service_name = string(T_CPP_DIR)+"/"+service_name_+".cc";
   f_service_.open(f_service_name.c_str());
 
   // Print header file includes
   f_header_ << autogen_comment();
   f_header_ <<
-    "#ifndef " << tservice->get_name() << "_h" << endl <<
-    "#define " << tservice->get_name() << "_h" << endl <<
+    "#ifndef " << service_name_ << "_H" << endl <<
+    "#define " << service_name_ << "_H" << endl <<
     endl <<
-    "#include \"TInterface.h\"" << endl <<
     "#include \"TDispatcher.h\"" << endl <<
-    "#include \"TProtocol.h\"" << endl <<   
+    "#include \"protocol/TProtocol.h\"" << endl <<
+    "#include \"" << program_name_ << "Types.h\"" << endl <<
     endl;
   f_service_ << autogen_comment();
   f_service_ <<
-    "#include \"" << tservice->get_name() << "_h\"" << endl << endl;
+    "#include \"" << service_name_ << ".h\"" << endl << endl;
 
   // Generate the three main parts of the service
   generate_service_interface(tservice);
@@ -174,7 +174,7 @@
  */
 void t_cpp_generator::generate_service_interface(t_service* tservice) {
   f_header_ <<
-    "class " << tservice->get_name() << " : public TInterface {" << endl <<
+    "class " << service_name_ << "If {" << endl <<
     " public: " << endl;
   indent_up(); 
   vector<t_function*> functions = tservice->get_functions();
@@ -184,13 +184,85 @@
       indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
   }
   f_header_ <<
-    indent() << "virtual ~" << tservice->get_name() << "() = 0;" << endl;
+    indent() << "virtual ~" << service_name_ << "If() {}" << endl;
   indent_down();
   f_header_ <<
     "}; " << endl << endl;
 }
 
 /**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice) {
+  // Generate the header portion
+  f_header_ <<
+    "class " << service_name_ << "Client : " <<
+    "public " << service_name_ << "If {" << endl <<
+    " public:" << endl; 
+  indent_up();
+  f_header_ <<
+    indent() << service_name_ << "Client" <<
+    "(TDispatcher* dispatcher, TProtocol* protocol) : " <<
+    "_dispatcher(dispatcher), _protocol(protocol) {}" << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  
+  f_header_ <<
+    " protected:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "TDispatcher* _dispatcher;" << endl <<
+    indent() << "TProtocol* _protocol;" << endl;
+  indent_down();  
+  f_header_ <<
+    "};" << endl <<
+    endl;
+  
+  // Generate client method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string prefix = service_name_ + "Client::";
+    f_service_ <<
+      function_signature(*f_iter, prefix) << " {" << endl;
+    indent_up();
+
+    indent(f_service_) <<
+      "std::string _argbuf = \"\";" << endl;
+    generate_serialize_struct("_argbuf", (*f_iter)->get_arglist());
+    indent(f_service_) <<
+      "std::string _sbuf = _protocol->writeFunction(\"" <<
+      (*f_iter)->get_name() << "\", _argbuf);" << endl;
+    indent(f_service_) <<
+      "std::string _rbuf = _dispatcher->dispatch(_sbuf);" << endl;
+
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      indent(f_service_) <<
+        "TBuf _tbuf((uint8_t*)_rbuf.data(), _rbuf.size());" << endl;
+      indent(f_service_) <<
+        type_name((*f_iter)->get_returntype()) << " _result;" << endl;
+      t_field result_field((*f_iter)->get_returntype(), "_result", 0);
+      generate_deserialize_field("_tbuf", &result_field);
+      indent(f_service_) <<
+        "return _result;" << endl;
+    } else {
+      indent(f_service_) <<
+        "return;" << endl;
+    }
+   
+    indent_down();
+    f_service_ <<
+      "}" << endl <<
+      endl;
+  }
+}
+
+/**
  * Generates a service server definition.
  *
  * @param tservice The service to generate a server for.
@@ -198,16 +270,24 @@
 void t_cpp_generator::generate_service_server(t_service* tservice) {
   // Generate the header portion
   f_header_ <<
-    "class " << tservice->get_name() << "Server : " <<
-    "public " << tservice->get_name() << ", " <<
+    "class " << service_name_ << "ServerIf : " <<
+    "public " << service_name_ << "If, " <<
     "public TDispatcher {" << endl <<
     " public: " << endl;
   indent_up();
   f_header_ << 
-    indent() << "std::string dispatch(const std::string& buff);" << endl <<
-    indent() << "virtual ~" << tservice->get_name() << "Server();" << endl;
+    indent() << service_name_ << "ServerIf(TProtocol* protocol) : " <<
+    "_protocol(protocol) {}" << endl <<
+    indent() << "std::string dispatch(const std::string& _in);" << endl <<
+    indent() << "virtual ~" << service_name_ << "ServerIf() {}" << endl;
   indent_down();
   f_header_ <<
+    " protected:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "TProtocol* _protocol;" << endl;
+  indent_down();  
+  f_header_ <<
     "};" << endl << endl;
 
   // Generate the dispatch methods
@@ -216,6 +296,54 @@
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     generate_dispatch_function(tservice, *f_iter);
   }
+
+  // Generate the server implementation
+  f_service_ <<
+    "std::string " << service_name_ << "ServerIf::" <<
+    "dispatch(const std::string& _in) {" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "TBuf _tbuf((uint8_t*)_in.data(), _in.size());" << endl <<
+    indent() << "std::string _fname = " <<
+                "_protocol->readFunction(_tbuf);" << endl <<
+    indent() << "std::string _result;" << endl;
+
+  bool first = true;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if (!first) {
+      f_service_ << " else ";
+    } else {
+      f_service_ << indent();
+      first = false;
+    }
+    f_service_ <<
+      "if (_fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl;
+    indent_up();
+    indent(f_service_) <<
+      "_result = dispatch_" << (*f_iter)->get_name() <<
+      "(_tbuf, this, _protocol);" << endl;
+    indent_down();
+    indent(f_service_) << "}";
+  }
+  indent(f_service_) <<
+    " else {" << endl;
+  indent_up();
+  f_service_ <<
+    indent() << "fprintf(stderr, \"Unknown function: '%s'\\n\", " <<
+    "_fname.c_str());" << endl <<
+    indent() << "_result = \"\";" << endl;
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl;
+
+  indent(f_service_) <<
+    "return _result;" << endl;
+
+  indent_down();
+  f_service_ <<
+    "}" << endl <<
+    endl;
 }
 
 /**
@@ -227,22 +355,32 @@
                                                  t_function* tfunction) {
   f_service_ <<
     "std::string dispatch_" << tfunction->get_name() <<
-    "(const char *_tbuf, " <<
-    tservice->get_name() << " *dispatcher, " <<
-    "TProtocol *protocol) {" << endl;
+    "(TBuf _tbuf, " <<
+    service_name_ << "If *_dispatcher, " <<
+    "const TProtocol *_protocol) {" << endl;
   indent_up();
 
-  // Create a field to represent this function's arguments
-  t_field arg_field(tfunction->get_arglist(), "_targs", 0);
+  // Get the struct of function call params
+  t_struct* arg_struct = tfunction->get_arglist();
 
-  generate_deserialize_struct(&arg_field);
+  // Declare the function arguments
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(f_service_) <<
+      declare_field(*f_iter, true) << endl;
+  }
 
+  // Deserialize the function arguments as a struct
+  generate_deserialize_struct("_tbuf", arg_struct);
+  
   // Generate the function call
-  indent(f_service_) <<
-    type_name(tfunction->get_returntype()) << " _tresult = dispatcher." <<
-    tfunction->get_name() << "(";
-  vector<t_field*> fields = tfunction->get_arglist()->get_members()->elems();
-  vector<t_field*>::iterator f_iter;
+  f_service_ << indent();
+  if (!tfunction->get_returntype()->is_void()) {
+    f_service_ << type_name(tfunction->get_returntype()) << " _result = ";
+  }
+  f_service_ <<
+    "_dispatcher->" << tfunction->get_name() << "(";
   bool first = true;
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     if (first) {
@@ -250,16 +388,21 @@
     } else {
       f_service_ << ", ";
     }
-    f_service_ << "_targs." << (*f_iter)->get_name();
+    f_service_ << (*f_iter)->get_name();
   }
   f_service_ << ");" << endl;
 
-  // Serialize the result
+  // Serialize the result into _sbuf
   indent(f_service_) <<
-    "std::string _tout = "";" << endl;
-  t_field out_field(tfunction->get_returntype(), "_tout", 0);
-  generate_serialize_field(&out_field);
-  
+    "std::string _sbuf = \"\";" << endl;
+
+  t_field result_field(tfunction->get_returntype(), "_result", 0);
+  generate_serialize_field("_sbuf", &result_field);
+
+  // Return the serialized buffer
+  indent(f_service_) <<
+    "return _sbuf;" << endl;
+
   indent_down();
   f_service_ <<
     "}" << endl <<
@@ -267,149 +410,390 @@
 }
 
 /**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(string src,
+                                                 t_field* tfield,
+                                                 string prefix) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    return;
+  }
+
+  if (type->is_struct()) {
+    generate_deserialize_struct(src,
+                                (t_struct*)(tfield->get_type()),
+                                prefix + tfield->get_name() + ".");
+  } else if (type->is_container()) {
+    generate_deserialize_container(src,
+                                   tfield->get_type(),
+                                   prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(f_service_) <<
+      prefix << tfield->get_name() << " = ";
+    if (type->is_enum()) {
+      f_service_ << "(" << type_name(type) << ")";
+    }
+    f_service_ <<
+      "_protocol->";
+    
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " +
+          src + ":" + tfield->get_name() + ":" + prefix;
+        break;
+      case t_base_type::TYPE_STRING:
+        f_service_ << "readString(" << src << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        f_service_ << "readByte(" << src << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        f_service_ << "readI32(" << src << ");";
+        break;
+      case t_base_type::TYPE_U32:
+        f_service_ << "readU32(" << src << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        f_service_ << "readI64(" << src << ");";
+        break;
+      case t_base_type::TYPE_U64:
+        f_service_ << "readU64(" << src << ");";
+        break;
+      default:
+        throw "compiler error: no C++ name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      f_service_ << "readI32(" << src << ");";
+    }
+    
+    f_service_ <<
+      endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type_name(type).c_str());
+  }
+}
+
+/**
  * Generates an unserializer for a variable. This makes two key assumptions,
  * first that there is a const char* variable named data that points to the
  * buffer for deserialization, and that there is a variable protocol which
  * is a reference to a TProtocol serialization object.
  */
-void t_cpp_generator::generate_deserialize_struct(t_field* tfield) {
-    t_struct* tstruct = (t_struct*)(tfield->get_type());
-  vector<t_field*> fields = tstruct->get_members()->elems();
-  vector<t_field*>::iterator f_iter;
+void t_cpp_generator::generate_deserialize_struct(string src,
+                                                  t_struct* tstruct,
+                                                  string prefix) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
 
-  indent(f_service_) <<
-    declare_field(tfield) << endl;
-  indent(f_service_) <<
-    "map<uint32_t,const char*> fmap = protocol.readFieldMap(_tbuf);" << endl;  
+  // Ensure that there are some fields
+  if (fields.size() == 0) {
+    return;
+  }
 
-  // Declare the fields up front
+  scope_up(f_service_);
+
+  // Read the struct fields from the protocol
+  string _struct = tmp("_struct");
+  indent(f_service_) <<
+    "std::map<uint32_t,TBuf> " << _struct <<
+    " = _protocol->readStruct(" << src << ");" << endl;
+  indent(f_service_) <<
+    "std::map<uint32_t,TBuf>::iterator _field;" << endl;
+
+  // Decleare a temp buffer for working with fields
+  string fbuf = tmp("_fbuf");
+
+  // Iterate over the fields and extract them
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Check for existence of the field
     indent(f_service_) <<
-      declare_field(*f_iter) << endl;
-    indent(f_service_) <<
-      "if (fmap.find(" << tfield->get_key() << ") != fmap.end()) {" << endl;
+      "if ((_field = " << _struct << ".find(" << (*f_iter)->get_key() <<
+      ")) != " << _struct << ".end()) {" <<
+      endl;
     indent_up();
+
+    // Copy the field buffer into temp buffer
     indent(f_service_) <<
-      "_tbuf = fmap[" << tfield->get_key() << "];" << endl;
-    generate_deserialize_field(*f_iter);
+      "TBuf& " << fbuf << " = _field->second;" << endl;
+
+    // Deserialize from the field's buffer
+    generate_deserialize_field(fbuf, *f_iter, prefix);
+
     indent_down();
     indent(f_service_) <<
       "}" << endl;
   }
+
+  scope_down(f_service_);
 }
 
-/**
- * Deserializes a field of any type.
- */
-void t_cpp_generator::generate_deserialize_field(t_field* tfield) {
-  t_type* type = tfield->get_type();
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  if (type->is_struct()) {
-    generate_deserialize_struct(tfield);
-  }
-
-  if (type->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-    switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      return;
-    case t_base_type::TYPE_STRING:
-      return;
-    case t_base_type::TYPE_BYTE:
-      return;
-    case t_base_type::TYPE_I32:
-      return;
-    case t_base_type::TYPE_U32:
-      return;
-    case t_base_type::TYPE_I64:
-      return;
-    case t_base_type::TYPE_U64:
-      return;
-    default:
-      throw "compiler error: no C++ name for base type " + tbase;
-    }
-  } else if (type->is_enum()) {
-    
-  }
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_cpp_generator::generate_service_client(t_service* tservice) {
-  // Generate the header portion
-  f_header_ <<
-    "class " << tservice->get_name() << "Client : " <<
-    "public " << tservice->get_name() << " {" << endl <<
-    " public:" << endl;
+void t_cpp_generator::generate_deserialize_container(string src,
+                                                     t_type* ttype,
+                                                     string prefix) {
+  scope_up(f_service_);
   
+  string size = tmp("_size");
+  indent(f_service_) <<
+    "uint32_t " << size << " = _protocol->readU32(" << src << ");" << endl;
+
+  string i = tmp("_i");
+  indent(f_service_) <<
+    "uint32_t " << i << ";" << endl;
+  indent(f_service_) <<
+    "for (" <<
+    i << " = 0; " << i << " < " << size << "; ++" << i << ") {" << endl;
   indent_up();
-  f_header_ <<
-    indent() << tservice->get_name() <<
-    "(TDispatcher& dispatcher, TProtocol& protocol);" << endl;
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_header_ <<
-      indent() << function_signature(*f_iter) << ";" << endl;
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(src, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(src, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(src, (t_list*)ttype, prefix);
   }
+
   indent_down();
-  
-  f_header_ <<
-    " private:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << "TDispatcher& dispatcher;" << endl <<
-    indent() << "TProtocol& protocol;" << endl;
-  indent_down();  
-  f_header_ <<
-    "};" << endl <<
-    endl;
+  indent(f_service_) <<
+    "}" << endl;
+
+  scope_down(f_service_);
 }
 
+
 /**
- * Deserializes a field of any type.
+ * Generates code to deserialize a map
  */
-void t_cpp_generator::generate_serialize_field(t_field* tfield) {
+void t_cpp_generator::generate_deserialize_map_element(string src,
+                                                       t_map* tmap,
+                                                       string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key, 0);
+  t_field fval(tmap->get_val_type(), val, 0);
+
+  indent(f_service_) <<
+    declare_field(&fkey) << endl;
+  indent(f_service_) <<
+    declare_field(&fval) << endl;
+
+  generate_deserialize_field(src, &fkey, "");
+  generate_deserialize_field(src, &fval, "");
+
+  indent(f_service_) <<
+    prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_set_element(string src,
+                                                       t_set* tset,
+                                                       string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem, 0);
+
+  indent(f_service_) <<
+    declare_field(&felem) << endl;
+
+  generate_deserialize_field(src, &felem, "");
+
+  indent(f_service_) <<
+    prefix << ".insert(" << elem << ");" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_list_element(string src,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem, 0);
+
+  indent(f_service_) <<
+    declare_field(&felem) << endl;
+
+  generate_deserialize_field(src, &felem, "");
+
+  indent(f_service_) <<
+    prefix << ".push_back(" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_cpp_generator::generate_serialize_field(string dest,
+                                               t_field* tfield,
+                                               string prefix) {
   t_type* type = tfield->get_type();
   while (type->is_typedef()) {
     type = ((t_typedef*)type)->get_type();
   }
-
-  if (type->is_struct()) {
-
+  
+  // Do nothing for void types
+  if (type->is_void()) {
+    return;
   }
 
-  if (type->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-    switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      return;
-    case t_base_type::TYPE_STRING:
-      return;
-    case t_base_type::TYPE_BYTE:
-      return;
-    case t_base_type::TYPE_I32:
-      return;
-    case t_base_type::TYPE_U32:
-      return;
-    case t_base_type::TYPE_I64:
-      return;
-    case t_base_type::TYPE_U64:
-      return;
-    default:
-      throw "compiler error: no C++ name for base type " + tbase;
-    }
-  } else if (type->is_enum()) {
+  if (type->is_struct()) {
+    generate_serialize_struct(dest,
+                              (t_struct*)(tfield->get_type()),
+                              prefix + tfield->get_name() + ".");
+  } else if (type->is_container()) {
+    generate_serialize_container(dest,
+                                 tfield->get_type(),
+                                 prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(f_service_) <<
+      dest << " += _protocol->";
     
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " +
+          dest + ":" + tfield->get_name() + ":" + prefix;
+        break;
+      case t_base_type::TYPE_STRING:
+        f_service_ << "writeString(" << prefix << tfield->get_name() << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        f_service_ << "writeByte(" << prefix << tfield->get_name() << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
+        break;
+      case t_base_type::TYPE_U32:
+        f_service_ << "writeU32(" << prefix << tfield->get_name() << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        f_service_ << "writeI64(" << prefix << tfield->get_name() << ");";
+        break;
+      case t_base_type::TYPE_U64:
+        f_service_ << "writeU64(" << prefix << tfield->get_name() << ");";
+        break;
+      default:
+        throw "compiler error: no C++ name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
+    } 
+    f_service_ << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type_name(type).c_str());
   }
 }
 
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_cpp_generator::generate_serialize_struct(string dest,
+                                                t_struct* tstruct,
+                                                string prefix) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Ensure that there are some fields
+  if (fields.size() == 0) {
+    return;
+  }
+
+  scope_up(f_service_);
+  string _struct = tmp("_struct");
+
+  indent(f_service_) <<
+    "std::map<uint32_t,std::string> " << _struct << ";" << endl;
+
+  // Serialize each of the fields into the map
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    ostringstream fdest;
+    fdest << _struct << "[" << (*f_iter)->get_key() << "]";
+    generate_serialize_field(fdest.str(), *f_iter, prefix);
+  }
+
+  // Write the struct map
+  indent(f_service_) <<
+    dest << " += _protocol->writeStruct(" << _struct << ");" << endl;
+
+  scope_down(f_service_);
+}
+
+void t_cpp_generator::generate_serialize_container(string dest,
+                                                   t_type* ttype,
+                                                   string prefix) {
+  scope_up(f_service_);
+  
+  indent(f_service_) <<
+    dest << " += _protocol->writeU32(" << prefix << ".size());" << endl;
+
+  string iter = tmp("_iter");
+  indent(f_service_) <<
+    type_name(ttype) << "::const_iterator " << iter << ";" << endl;
+  indent(f_service_) <<
+    "for (" << iter << " = " << prefix  << ".begin(); " <<
+    iter << " != " << prefix << ".end(); " <<
+    "++" << iter << ") {" << endl;
+  indent_up();
+  
+  if (ttype->is_map()) {
+    generate_serialize_map_element(dest, (t_map*)ttype, iter);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(dest, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(dest, (t_list*)ttype, iter);
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl;  
+  
+  scope_down(f_service_);  
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_cpp_generator::generate_serialize_map_element(string dest,
+                                                     t_map* tmap,
+                                                     string iter) {
+  t_field kfield(tmap->get_key_type(), iter + "->first", 0);
+  generate_serialize_field(dest, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), iter + "->second", 0);
+  generate_serialize_field(dest, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cpp_generator::generate_serialize_set_element(string dest,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), "(*" + iter + ")", 0);
+  generate_serialize_field(dest, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cpp_generator::generate_serialize_list_element(string dest,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), "(*" + iter + ")", 0);
+  generate_serialize_field(dest, &efield, "");
+}
 
 /**
  * Generates a comment about this code being autogenerated.
@@ -436,6 +820,17 @@
 string t_cpp_generator::type_name(t_type* ttype) {
   if (ttype->is_base_type()) {
     return base_type_name(((t_base_type*)ttype)->get_base());
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*) ttype;
+    return "std::map<" +
+      type_name(tmap->get_key_type()) + ", " +
+      type_name(tmap->get_val_type()) + "> ";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*) ttype;
+    return "std::set<" + type_name(tset->get_elem_type()) + "> ";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*) ttype;
+    return "std::list<" + type_name(tlist->get_elem_type()) + "> ";
   } else {
     return ttype->get_name();
   }
@@ -472,9 +867,38 @@
  *
  * @param ttype The type
  */
-string t_cpp_generator::declare_field(t_field* tfield) {
+string t_cpp_generator::declare_field(t_field* tfield, bool init) {
   // TODO(mcslee): do we ever need to initialize the field?
-  return type_name(tfield->get_type()) + " " + tfield->get_name() + ";";
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    t_type* type = tfield->get_type();
+    while (type->is_typedef()) {
+      type = ((t_typedef*)type)->get_type();
+    }
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = \"\"";
+        break;
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_U32:
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_U64:
+        result += " = 0";
+        break;
+      default:
+        throw "compiler error: no C++ initializer for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      result += " = (" + type_name(type) + ")0";
+    }
+  }
+  return result + ";";
 }
 
 /**
@@ -483,20 +907,22 @@
  * @param tfunction Function definition
  * @return String of rendered function definition
  */
-string t_cpp_generator::function_signature(t_function* tfunction) {
+string t_cpp_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  t_type* ttype = tfunction->get_returntype();
   return
-    type_name(tfunction->get_returntype()) + " " + tfunction->get_name() +
-    "(" + field_list(tfunction->get_arglist()->get_members()) + ")";
+    type_name(ttype) + " " + prefix + tfunction->get_name() +
+    "(" + argument_list(tfunction->get_arglist()) + ")";
 }
 
 /**
  * Renders a field list
  */
-string t_cpp_generator::field_list(t_list* tlist) {
+string t_cpp_generator::argument_list(t_struct* tstruct) {
   string result = "";
 
-  vector<t_field*> fields = tlist->elems();
-  vector<t_field*>::iterator f_iter;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
   bool first = true;
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     if (first) {
diff --git a/compiler/src/generate/t_cpp_generator.h b/compiler/src/generate/t_cpp_generator.h
index 87eb72a..079a26d 100644
--- a/compiler/src/generate/t_cpp_generator.h
+++ b/compiler/src/generate/t_cpp_generator.h
@@ -3,13 +3,15 @@
 
 #include <string>
 #include <fstream>
+#include <iostream>
+#include <vector>
 
 #include "t_generator.h"
 
 #define T_CPP_DIR "gen-cpp"
 
 /**
- * C++ code generator
+ * C++ code generator.
  *
  * @author Mark Slee <mcslee@facebook.com>
  */
@@ -19,35 +21,98 @@
   ~t_cpp_generator() {}
 
   /** Init and close methods */
+
   void init_generator(t_program *tprogram);
   void close_generator();
 
   /** Program-level generation functions */
+
   void generate_typedef (t_typedef*  ttypedef);
   void generate_enum    (t_enum*     tenum);
   void generate_struct  (t_struct*   tstruct);
   void generate_service (t_service*  tservice);
 
   /** Service-level generation functions */
+
   void generate_service_interface (t_service* tservice);
-  void generate_service_server    (t_service* tservice);
   void generate_service_client    (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_dispatch_function (t_service* tservice, t_function* tfunction);
 
   /** Serialization constructs */
-  void generate_dispatch_function (t_service* tservice, t_function* tfunction);
-  void generate_deserialize_struct(t_field* tfield);
-  void generate_deserialize_field(t_field* tfield);
+
+  void generate_deserialize_field        (std::string src,
+                                          t_field*    tfield, 
+                                          std::string prefix="");
+  
+  void generate_deserialize_struct       (std::string src,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+  
+  void generate_deserialize_container    (std::string src,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+  
+  void generate_deserialize_set_element  (std::string src,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::string src,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::string src,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::string dest,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::string dest,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::string dest,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::string dest,
+                                          t_map*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_set_element    (std::string dest,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::string dest,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /** Scoping */
+
+  void scope_up(std::ostream& out) {
+    indent(out) << "{" << std::endl;
+    indent_up();
+  }
+
+  void scope_down(std::ostream& out) {
+    indent_down();
+    indent(out) << "}" << std::endl;
+  }
 
   /** Helper rendering functions */
+
   std::string autogen_comment();
   std::string type_name(t_type* ttype);
   std::string base_type_name(t_base_type::t_base tbase);
-  std::string declare_field(t_field* tfield);
-  std::string function_signature(t_function* tfunction);
-  std::string field_list(t_list* tlist);
+  std::string declare_field(t_field* tfield, bool init=false);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string argument_list(t_struct* tstruct);
   
  private:
   /** File streams */
+
   std::ofstream f_types_;
   std::ofstream f_header_;
   std::ofstream f_service_;
diff --git a/compiler/src/generate/t_generator.cc b/compiler/src/generate/t_generator.cc
index 0ba44ac..d68e66d 100644
--- a/compiler/src/generate/t_generator.cc
+++ b/compiler/src/generate/t_generator.cc
@@ -9,6 +9,9 @@
  * @param program The thrift program to compile into C++ source
  */
 void t_generator::generate_program(t_program *tprogram) {
+  // Set program name
+  program_name_ = get_program_name(tprogram);
+
   // Initialize the generator
   init_generator(tprogram);
 
@@ -37,6 +40,7 @@
   vector<t_service*> services = tprogram->get_services();
   vector<t_service*>::iterator sv_iter;
   for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    service_name_ = get_service_name(*sv_iter);
     generate_service(*sv_iter);
   }
 
diff --git a/compiler/src/generate/t_generator.h b/compiler/src/generate/t_generator.h
index 71d0318..be0b83e 100644
--- a/compiler/src/generate/t_generator.h
+++ b/compiler/src/generate/t_generator.h
@@ -3,6 +3,7 @@
 
 #include <string>
 #include <iostream>
+#include <sstream>
 #include "parse/t_program.h"
 
 /**
@@ -14,7 +15,7 @@
  */
 class t_generator {
  public:
-  t_generator() {}
+  t_generator() { tmp_ = 0; }
   virtual ~t_generator() {}
 
   /**
@@ -26,16 +27,37 @@
 
  protected:
   /** Optional methods that may be imlemented by subclasses. */
+
   virtual void init_generator    (t_program*  tprogram) {}
   virtual void close_generator   () {}
 
   /** Pure virtual methods implemented by the generator subclasses. */
+
   virtual void generate_typedef  (t_typedef*  ttypedef) = 0;
   virtual void generate_enum     (t_enum*     tenum)    = 0;
   virtual void generate_struct   (t_struct*   tstruct)  = 0;
   virtual void generate_service  (t_service*  tservice) = 0;
 
+  /** Method to get the program name, may be overridden */
+
+  virtual std::string get_program_name(t_program* tprogram) {
+    return tprogram->get_name();
+  }
+
+  /** Method to get the service name, may be overridden */
+  virtual std::string get_service_name(t_service* tservice) {
+    return tservice->get_name();
+  }
+
+  /** Creates a unique temporary variable name. */
+  std::string tmp(std::string name) {
+    std::ostringstream out;
+    out << name << tmp_++;
+    return out.str();
+  }
+
   /** Indentation level modifiers */
+
   void indent_up()   { ++indent_; }
   void indent_down() { --indent_; }
 
@@ -49,15 +71,24 @@
     return ind;
   }
 
-  /** Indentation wrapper */
+  /** Indentation utility wrapper */
   std::ostream& indent(std::ostream &os) {
     return os << indent();
   }
 
+ protected:
+  /** Quick accessor for formatted program name */
+  std::string program_name_;
+
+  /** Quick accessor for formatted service name */
+  std::string service_name_;
+
  private:
   /** Indentation level */
   int indent_;
 
+  /** Temporary variable counter */
+  int tmp_;
 };
 
 #endif
diff --git a/compiler/src/main.cc b/compiler/src/main.cc
index cc126f8..8d8263c 100644
--- a/compiler/src/main.cc
+++ b/compiler/src/main.cc
@@ -137,6 +137,7 @@
   
   // Parse it
   g_program = new t_program(name);
+
   if (yyparse() != 0) {
     failure("Parser error.");
   }
@@ -146,6 +147,8 @@
     t_cpp_generator* cpp = new t_cpp_generator();
     cpp->generate_program(g_program);
     delete cpp;
+  } catch (string s) {
+    printf("Error: %s\n", s.c_str());
   } catch (const char* exc) {
     printf("Error: %s\n", exc);
   }
diff --git a/compiler/src/parse/t_base_type.h b/compiler/src/parse/t_base_type.h
index bc96122..f6cc197 100644
--- a/compiler/src/parse/t_base_type.h
+++ b/compiler/src/parse/t_base_type.h
@@ -25,6 +25,7 @@
     t_type(name), base_(base) {}
     
   t_base get_base() const { return base_; }
+  bool is_void() const { return base_ == TYPE_VOID; }
   bool is_base_type() const { return true; }
     
  private:
diff --git a/compiler/src/parse/t_list.h b/compiler/src/parse/t_list.h
index 736ac48..65874cc 100644
--- a/compiler/src/parse/t_list.h
+++ b/compiler/src/parse/t_list.h
@@ -1,27 +1,19 @@
 #ifndef T_LIST_H
 #define T_LIST_H
 
-#include "t_field.h"
-#include <vector>
+#include "t_type.h"
 
-/**
- * List of elements.
- *
- * @author Mark Slee <mcslee@facebook.com>
- */
-class t_list {
+class t_list : public t_type {
  public:
-  t_list() {}
+  t_list(t_type* elem_type) : elem_type_(elem_type) {}
   ~t_list() {}
 
-  /** Add a new field to the list */
-  void append(t_field* elem) { list_.push_back(elem); }
-
-  /** Retrieve the list contents */
-  const std::vector<t_field*>& elems() const { return list_; }
+  t_type* get_elem_type() const { return elem_type_; }
+  bool is_list() const { return true; }
 
  private:
-  std::vector<t_field*> list_;
+  t_type* elem_type_;
 };
 
 #endif
+
diff --git a/compiler/src/parse/t_map.h b/compiler/src/parse/t_map.h
new file mode 100644
index 0000000..1f61843
--- /dev/null
+++ b/compiler/src/parse/t_map.h
@@ -0,0 +1,19 @@
+#ifndef T_MAP_H
+#define T_MAP_H
+
+class t_map : public t_type {
+ public:
+  t_map(t_type* key_type, t_type* val_type) :
+    key_type_(key_type), val_type_(val_type) {}
+  ~t_map() {}
+
+  t_type* get_key_type() const { return key_type_; }
+  t_type* get_val_type() const { return val_type_; }
+  bool is_map() const { return true; }
+
+ private:
+  t_type* key_type_;
+  t_type* val_type_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_program.h b/compiler/src/parse/t_program.h
index fd35799..cda24c6 100644
--- a/compiler/src/parse/t_program.h
+++ b/compiler/src/parse/t_program.h
@@ -1,6 +1,7 @@
 #ifndef T_PROGRAM_H
 #define T_PROGRAM_H
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -9,6 +10,9 @@
 #include "t_enum.h"
 #include "t_struct.h"
 #include "t_service.h"
+#include "t_list.h"
+#include "t_map.h"
+#include "t_set.h"
 
 /**
  * Top level class representing an entire thrift program. A program consists
@@ -52,12 +56,6 @@
   const std::vector<t_struct*>&  get_structs()  const { return structs_;  }
   const std::vector<t_service*>& get_services() const { return services_; }
 
-  // New program element addition
-  void add_typedef(t_typedef *td) { typedefs_.push_back(td); }
-  void add_enum   (t_enum *te)    { enums_.push_back(te);    }
-  void add_struct (t_struct *ts)  { structs_.push_back(ts);  }
-  void add_service(t_service *ts) { services_.push_back(ts); }
-
   // Accessors for global types
   t_type* get_void_type()   const { return type_void;   }
   t_type* get_string_type() const { return type_string; }
@@ -67,6 +65,31 @@
   t_type* get_i64_type()    const { return type_i64;    }
   t_type* get_u64_type()    const { return type_u64;    }
 
+  // Custom data type lookup
+  void add_custom_type(std::string name, t_type* type) {
+    custom_types_[name] = type;
+  }
+  t_type* get_custom_type(std::string name) {
+    return custom_types_[name];
+  }
+
+  // New program element addition
+  void add_typedef(t_typedef* td) {
+    typedefs_.push_back(td);
+    add_custom_type(td->get_symbolic(), td);
+  }
+  void add_enum(t_enum* te) {
+    enums_.push_back(te);
+    add_custom_type(te->get_name(), te);
+  }
+  void add_struct(t_struct* ts) {
+    structs_.push_back(ts);
+    add_custom_type(ts->get_name(), ts);
+  }
+  void add_service(t_service* ts) {
+    services_.push_back(ts);
+  }
+
  private:
   // Name
   std::string name_;
@@ -76,7 +99,10 @@
   std::vector<t_enum*>    enums_;
   std::vector<t_struct*>  structs_;
   std::vector<t_service*> services_;
-  
+
+  // Type map
+  std::map<std::string, t_type*> custom_types_;
+
   // Global base types
   t_type* type_void;
   t_type* type_string;
diff --git a/compiler/src/parse/t_set.h b/compiler/src/parse/t_set.h
new file mode 100644
index 0000000..3d34ace
--- /dev/null
+++ b/compiler/src/parse/t_set.h
@@ -0,0 +1,18 @@
+#ifndef T_SET_H
+#define T_SET_H
+
+#include "t_type.h"
+
+class t_set : public t_type {
+ public:
+  t_set(t_type* elem_type) : elem_type_(elem_type) {}
+  ~t_set() {}
+
+  t_type* get_elem_type() const { return elem_type_; }
+  bool is_set() const { return true; }
+
+ private:
+  t_type* elem_type_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_struct.h b/compiler/src/parse/t_struct.h
index fcc00e7..38eb750 100644
--- a/compiler/src/parse/t_struct.h
+++ b/compiler/src/parse/t_struct.h
@@ -5,19 +5,24 @@
 #include <string>
 
 #include "t_type.h"
-#include "t_list.h"
+#include "t_field.h"
 
 class t_struct : public t_type {
  public:
-  t_struct(std::string name, t_list* members) :
-    t_type(name), members_(members) {}
+  t_struct() {}
   ~t_struct() {}
 
-  t_list* get_members() { return members_; }
-  bool is_struct() { return true; }
+  /** Set the struct name */
+  void set_name(const std::string& name) { name_ = name; }
+
+  /** Add a new field to the list */
+  void append(t_field* elem) { members_.push_back(elem); }
+
+  const std::vector<t_field*>& get_members() { return members_; }
+  bool is_struct() const { return true; }
 
  private:
-  t_list* members_;
+  std::vector<t_field*> members_;
 };
 
 #endif
diff --git a/compiler/src/parse/t_type.h b/compiler/src/parse/t_type.h
index 436c59e..6703bfa 100644
--- a/compiler/src/parse/t_type.h
+++ b/compiler/src/parse/t_type.h
@@ -14,10 +14,16 @@
 
   virtual const std::string& get_name() const { return name_; }
 
+  virtual bool is_void()      const { return false; }
   virtual bool is_base_type() const { return false; }
   virtual bool is_typedef()   const { return false; }
   virtual bool is_enum()      const { return false; }
   virtual bool is_struct()    const { return false; }
+  virtual bool is_list()      const { return false; }
+  virtual bool is_set()       const { return false; }
+  virtual bool is_map()       const { return false; }
+
+  bool is_container() const { return is_map() || is_set() || is_list(); }
 
  protected:
   t_type() {}
diff --git a/compiler/src/thrift.l b/compiler/src/thrift.l
index 5164c89..61a0ce3 100644
--- a/compiler/src/thrift.l
+++ b/compiler/src/thrift.l
@@ -23,7 +23,7 @@
 whitespace   ([ \t\r\n]*)
 multicomm    ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
 comment      ("//"[^\n]*)
-symbol       ([\,\{\}\(\)\=])
+symbol       ([\,\{\}\(\)\=<>])
 
 %%
 
diff --git a/compiler/src/thrift.y b/compiler/src/thrift.y
index f0fa3c4..a406c8e 100644
--- a/compiler/src/thrift.y
+++ b/compiler/src/thrift.y
@@ -27,7 +27,6 @@
   t_service*  tservice;
   t_function* tfunction;
   t_field*    tfield;
-  t_list*     tlist;
   t_constant* tconstant;
 }
 
@@ -63,13 +62,17 @@
 
 /** Types */
 %type<ttype>     BaseType
+%type<ttype>     ContainerType
+%type<ttype>     MapType
+%type<ttype>     SetType
+%type<ttype>     ListType
 
 %type<ttypedef>  Typedef
 %type<ttype>     DefinitionType
 
 %type<tfield>    Field
 %type<ttype>     FieldType
-%type<tlist>     FieldList
+%type<tstruct>   FieldList
 
 %type<tenum>     Enum
 %type<tenum>     EnumDefList
@@ -130,7 +133,6 @@
   tok_typedef DefinitionType tok_identifier
     {
       pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
-      
       t_typedef *td = new t_typedef($2, $3);
       $$ = td;
     }
@@ -165,10 +167,10 @@
 EnumDef:
   tok_identifier '=' tok_int_constant
     {
+      pdebug("EnumDef => tok_identifier = tok_int_constant");
       if ($3 < 0) {
         printf("WARNING (%d): Negative value supplied for enum %s.\n", yylineno, $1);
       }
-      pdebug("EnumDef => tok_identifier = tok_int_constant");
       $$ = new t_constant($1, $3);
     }
 |
@@ -182,7 +184,8 @@
   tok_struct tok_identifier '{' FieldList '}'
     {
       pdebug("Struct -> tok_struct tok_identifier { FieldList }");
-      $$ = new t_struct($2, $4);
+      $4->set_name($2);
+      $$ = $4;
       y_field_val = 0;
     }
 
@@ -210,8 +213,7 @@
 Function:
   FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
     {
-      t_struct* fun_args = new t_struct("__targs", $5);
-      $$ = new t_function($1, $3, fun_args);
+      $$ = new t_function($1, $3, $5);
       y_field_val = 0;
     }
 
@@ -231,26 +233,29 @@
 | Field
     {
       pdebug("FieldList -> Field");
-      $$ = new t_list;
+      $$ = new t_struct;
       $$->append($1);
     }
 |
     {
       pdebug("FieldList -> ");
-      $$ = new t_list;
+      $$ = new t_struct;
     }
 
 Field:
   FieldType tok_identifier '=' tok_int_constant
     {
+      pdebug("Field -> FieldType tok_identifier = tok_int_constant");
       if ($4 < 0) {
         yyerror("Negative value (%d) not allowed as a field key.", $4);
+        exit(1);
       }
       $$ = new t_field($1, $2, (uint32_t)$4);
       y_field_val = $4+1;
     }
 | FieldType tok_identifier
     {
+      pdebug("Field -> FieldType tok_identifier");
       printf("WARNING (%d): No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
       $$ = new t_field($1, $2, y_field_val++);
     }
@@ -261,25 +266,42 @@
       pdebug("DefinitionType -> BaseType");
       $$ = $1;
     }
+| ContainerType
+    {
+      pdebug("DefinitionType -> ContainerType");
+      $$ = $1;
+    }
 
 FunctionType:
   FieldType
     {
+      pdebug("FunctionType -> FieldType");
       $$ = $1;
     }
 | tok_void
     {
+      pdebug("FunctionType -> tok_void");
       $$ = g_program->get_void_type();
     }
 
 FieldType:
   tok_identifier
     {
-      /** TODO(mcslee): Dynamic type lookup */
-      yyerror("No dynamic type lookup yet.");
+      pdebug("FieldType -> tok_identifier");
+      $$ = g_program->get_custom_type($1);
+      if ($$ == NULL) {
+        yyerror("Type \"%s\" has not been defined.", $1);
+        exit(1);
+      }
     }
 | BaseType
     {
+      pdebug("FieldType -> BaseType");
+      $$ = $1;
+    }
+| ContainerType
+    {
+      pdebug("FieldType -> ContainerType");
       $$ = $1;
     }
 
@@ -315,4 +337,42 @@
       $$ = g_program->get_u64_type();
     }
 
+ContainerType:
+  MapType
+    {
+      pdebug("ContainerType -> MapType");
+      $$ = $1;
+    }
+| SetType
+    {
+      pdebug("ContainerType -> SetType");
+      $$ = $1;
+    }
+| ListType
+    {
+      pdebug("ContainerType -> ListType");
+      $$ = $1;
+    }
+
+MapType:
+  tok_map '<' FieldType ',' FieldType '>'
+    {
+      pdebug("MapType -> tok_map <FieldType, FieldType>");
+      $$ = new t_map($3, $5);
+    }
+
+SetType:
+  tok_set '<' FieldType '>'
+    {
+      pdebug("SetType -> tok_set<FieldType>");
+      $$ = new t_set($3);
+    }
+
+ListType:
+  tok_list '<' FieldType '>'
+    {
+      pdebug("ListType -> tok_list<FieldType>");
+      $$ = new t_list($3);
+    }
+
 %%
diff --git a/compiler/test/test.thrift b/compiler/test/test.thrift
deleted file mode 100644
index b2baab3..0000000
--- a/compiler/test/test.thrift
+++ /dev/null
@@ -1,27 +0,0 @@
-typedef i32 gozone_t
-
-enum numberz
-{
-  ONE = 1,
-  TWO,
-  THREE,
-  FIVE = 5,
-  SIX,
-  EIGHT = 8
-}
-
-struct things
-{
-  u32 first_num,
-  u32 second_num,
-  u32 third_num,
-  u32 fourth_num
-}
-
-service worker
-{
-  void   funky_void()
-  string funky_string(string thing)
-  u32    funky_u32(u32 thing)
-  i32    funky_i32(i32 thing)
-}
diff --git a/lib/cpp/Makefile b/lib/cpp/Makefile
new file mode 100644
index 0000000..2045dba
--- /dev/null
+++ b/lib/cpp/Makefile
@@ -0,0 +1,28 @@
+# Makefile for Thrift C++ library.
+# 
+# Author:
+#   Mark Slee <mcslee@facebook.com>
+
+target: libthrift
+
+# Tools
+LD    = g++
+LDFL  = -shared -Wall -I. -fPIC -Wl,-soname=libthrift.so
+
+# Source files
+SRCS  = client/TSimpleClient.cc \
+	protocol/TBinaryProtocol.cc \
+	server/TSimpleServer.cc \
+	transport/TSocket.cc \
+	transport/TServerSocket.cc
+
+# Linked library
+libthrift:
+	$(LD) -o libthrift.so $(LDFL) $(SRCS)
+
+clean:
+	rm -f libthrift.so
+
+# Install
+install: libthrift
+	sudo install libthrift.so /usr/local/lib
diff --git a/lib/cpp/TDispatcher.h b/lib/cpp/TDispatcher.h
new file mode 100644
index 0000000..f8ff847
--- /dev/null
+++ b/lib/cpp/TDispatcher.h
@@ -0,0 +1,22 @@
+#ifndef T_DISPATCHER_H
+#define T_DISPATCHER_H
+
+#include <string>
+
+/**
+ * A dispatcher is a generic object that accepts an input buffer and returns
+ * a buffer. It can be used in a variety of ways, i.e. as a client that
+ * sends data over the network and returns a response, or as a server that
+ * reads an input and returns an output.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TDispatcher {
+ public:
+  virtual ~TDispatcher() {};
+  virtual std::string dispatch(const std::string& s) = 0;
+ protected:
+  TDispatcher() {}
+};
+
+#endif
diff --git a/lib/cpp/Thrift.h b/lib/cpp/Thrift.h
new file mode 100644
index 0000000..04fbaa1
--- /dev/null
+++ b/lib/cpp/Thrift.h
@@ -0,0 +1,10 @@
+#ifndef THRIFT_H
+#define THRIFT_H
+
+#include <sys/types.h>
+#include <string>
+#include <map>
+#include <list>
+#include <set>
+
+#endif
diff --git a/lib/cpp/client/TClient.h b/lib/cpp/client/TClient.h
new file mode 100644
index 0000000..73dd093
--- /dev/null
+++ b/lib/cpp/client/TClient.h
@@ -0,0 +1,16 @@
+#ifndef T_CLIENT_H
+#define T_CLIENT_H
+
+#include "TDispatcher.h"
+
+class TClient : public TDispatcher {
+ public:
+  virtual ~TClient() {}
+  virtual bool open() = 0;
+  virtual void close() = 0;
+ protected:
+  TClient() {}
+};
+
+#endif
+
diff --git a/lib/cpp/client/TSimpleClient.cc b/lib/cpp/client/TSimpleClient.cc
new file mode 100644
index 0000000..9069c91
--- /dev/null
+++ b/lib/cpp/client/TSimpleClient.cc
@@ -0,0 +1,44 @@
+#include "TSimpleClient.h"
+using std::string;
+
+TSimpleClient::TSimpleClient(TTransport* transport) :
+  transport_(transport) {}
+
+bool TSimpleClient::open() {
+  return transport_->open();
+}
+
+void TSimpleClient::close() {
+  transport_->close();
+}
+
+std::string TSimpleClient::dispatch(const string& s) {
+  // Write size header
+  int32_t size = s.size();
+  // fprintf(stderr, "Writing size header %d to server\n", size);
+  transport_->write(string((char*)&size, 4));
+
+  // Write data payload
+  // fprintf(stderr, "Writing %d byte payload to server\n", (int)s.size());
+  transport_->write(s);
+
+  // Read response size
+  // fprintf(stderr, "Reading 4-byte response size header\n");
+  string response;
+  transport_->read(response, 4);
+  size = *(int32_t*)response.data();
+
+  // Read response data
+  if (size < 0) {
+    // TODO(mcslee): Handle exception
+    // fprintf(stderr, "Exception case! Response size < 0\n");
+    return "";
+  } else {
+    // fprintf(stderr, "Reading %d byte response payload\n", size);
+    transport_->read(response, size);
+    // TODO(mcslee): Check that we actually read enough data
+    // fprintf(stderr, "Done reading payload, returning.\n");
+    return response;
+  }
+}
+
diff --git a/lib/cpp/client/TSimpleClient.h b/lib/cpp/client/TSimpleClient.h
new file mode 100644
index 0000000..249afe5
--- /dev/null
+++ b/lib/cpp/client/TSimpleClient.h
@@ -0,0 +1,21 @@
+#ifndef T_SIMPLE_CLIENT_H
+#define T_SIMPLE_CLIENT_H
+
+#include "client/TClient.h"
+#include "transport/TTransport.h"
+
+class TSimpleClient : public TClient {
+ public:
+  TSimpleClient(TTransport* transport);
+  ~TSimpleClient() {}
+
+  bool open();
+  void close();
+  std::string dispatch(const std::string& in);
+
+ protected:
+  TTransport* transport_;
+};
+
+#endif
+
diff --git a/lib/cpp/protocol/TBinaryProtocol.cc b/lib/cpp/protocol/TBinaryProtocol.cc
new file mode 100644
index 0000000..4c10bab
--- /dev/null
+++ b/lib/cpp/protocol/TBinaryProtocol.cc
@@ -0,0 +1,140 @@
+#include "protocol/TBinaryProtocol.h"
+using namespace std;
+
+string TBinaryProtocol::readFunction(TBuf& buf) const {
+  // Let readString increment the buffer position
+  return readString(buf);
+}
+
+string TBinaryProtocol::writeFunction(const string& name,
+                                      const string& args) const{
+  return writeString(name) + args;
+}
+
+map<uint32_t, TBuf> TBinaryProtocol::readStruct(TBuf& buf) const {
+  map<uint32_t, TBuf> fieldMap;
+  
+  if (buf.len < 4) {
+    return fieldMap;
+  }
+  uint32_t total_size = readU32(buf);
+  if (buf.len < total_size) {
+    // Data looks corrupt, we don't have that much, we will try to read what
+    // we can but be sure not to go over
+    total_size = buf.len;
+  }
+
+  // Field headers are 8 bytes, 4 byte fid + 4 byte length
+  while (total_size > 0 && buf.len > 8) {
+    uint32_t fid  = readU32(buf);
+    uint32_t flen = readU32(buf);
+    if (flen > buf.len) {
+      // flen corrupt, there isn't that much data left
+      break;
+    }
+    fieldMap.insert(make_pair(fid, TBuf(buf.data, flen)));
+    buf.data += flen;
+    buf.len  -= flen;
+    total_size -= 8 + flen;
+  }
+
+  return fieldMap;
+}
+
+string TBinaryProtocol::writeStruct(const map<uint32_t,string>& s) const {
+  string result = "";
+  map<uint32_t,string>::const_iterator s_iter;
+  for (s_iter = s.begin(); s_iter != s.end(); ++s_iter) {
+    result += writeU32(s_iter->first);
+    result += writeU32(s_iter->second.size());
+    result += s_iter->second;
+  }
+  return writeU32(result.size()) + result;
+}
+
+string TBinaryProtocol::readString(TBuf& buf) const {
+  uint32_t len = readU32(buf);
+  if (len == 0) {
+    return "";
+  }
+  string result((const char*)(buf.data), len);
+  buf.data += len;
+  buf.len  -= len;
+  return result;
+}
+
+uint8_t TBinaryProtocol::readByte(TBuf& buf) const {
+  if (buf.len == 0) {
+    return 0;
+  }
+  uint8_t result = (uint8_t)buf.data[0];
+  buf.data += 1;
+  buf.len  -= 1;
+  return result;
+}
+
+uint32_t TBinaryProtocol::readU32(TBuf& buf) const {
+  if (buf.len < 4) {
+    return 0;
+  }
+  uint32_t result = *(uint32_t*)buf.data;
+  buf.data += 4;
+  buf.len  -= 4;
+  return result;
+}
+
+int32_t TBinaryProtocol::readI32(TBuf& buf) const {
+  if (buf.len < 4) {
+    return 0;
+  }
+  int32_t result = *(int32_t*)buf.data;
+  buf.data += 4;
+  buf.len  -= 4;
+  return result; 
+}
+
+uint64_t TBinaryProtocol::readU64(TBuf& buf) const {
+  if (buf.len < 8) {
+    return 0;
+  }
+  uint64_t result = *(uint64_t*)buf.data;
+  buf.data += 8;
+  buf.len  -= 8;
+  return result;
+}
+
+int64_t TBinaryProtocol::readI64(TBuf& buf) const {
+  if (buf.len < 8) {
+    return 0;
+  }
+  int64_t result = *(int64_t*)buf.data;
+  buf.data += 8;
+  buf.len  -= 8;
+  return result;
+}
+
+string TBinaryProtocol::writeString(const string& str) const {
+  uint32_t size = str.size();
+  string result = string((const char*)&size, 4);
+  return result + str;
+}
+
+string TBinaryProtocol::writeByte(const uint8_t byte) const {
+  return string((const char*)&byte, 1);
+}
+
+string TBinaryProtocol::writeU32(const uint32_t u32) const {
+  return string((const char*)&u32, 4);
+}
+
+string TBinaryProtocol::writeI32(int32_t i32) const {
+  return string((const char*)&i32, 4);
+}
+
+string TBinaryProtocol::writeU64(uint64_t u64) const {
+  return string((const char*)&u64, 8);
+}
+
+string TBinaryProtocol::writeI64(int64_t i64) const {
+  return string((const char*)&i64, 8);
+}
diff --git a/lib/cpp/protocol/TBinaryProtocol.h b/lib/cpp/protocol/TBinaryProtocol.h
new file mode 100644
index 0000000..976c383
--- /dev/null
+++ b/lib/cpp/protocol/TBinaryProtocol.h
@@ -0,0 +1,42 @@
+#ifndef T_BINARY_PROTOCOL_H
+#define T_BINARY_PROTOCOL_H
+
+#include "protocol/TProtocol.h"
+
+/**
+ * The default binary protocol for thrift. Writes all data in a very basic
+ * binary format, essentially just spitting out the raw bytes.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TBinaryProtocol : public TProtocol {
+ public:
+  TBinaryProtocol() {}
+  ~TBinaryProtocol() {}
+
+  std::string
+    readFunction(TBuf& buf) const;
+  std::string
+    writeFunction(const std::string& name, const std::string& args) const;
+
+  std::map<uint32_t, TBuf>
+    readStruct(TBuf& buf) const;
+  std::string
+    writeStruct(const std::map<uint32_t,std::string>& s) const;
+
+  std::string readString  (TBuf& buf) const;
+  uint8_t     readByte    (TBuf& buf) const;
+  uint32_t    readU32     (TBuf& buf) const;
+  int32_t     readI32     (TBuf& buf) const;
+  uint64_t    readU64     (TBuf& buf) const;
+  int64_t     readI64     (TBuf& buf) const;
+
+  std::string writeString (const std::string& str) const;
+  std::string writeByte   (const uint8_t  byte)    const;
+  std::string writeU32    (const uint32_t u32)     const;
+  std::string writeI32    (const int32_t  i32)     const;
+  std::string writeU64    (const uint64_t u64)     const;
+  std::string writeI64    (const int64_t  i64)     const;
+};
+
+#endif
diff --git a/lib/cpp/protocol/TProtocol.h b/lib/cpp/protocol/TProtocol.h
new file mode 100644
index 0000000..1f2e0c8
--- /dev/null
+++ b/lib/cpp/protocol/TProtocol.h
@@ -0,0 +1,88 @@
+#ifndef T_PROTOCOL_H
+#define T_PROTOCOL_H
+
+#include <sys/types.h>
+#include <string>
+#include <map>
+
+/** Forward declaration for TProtocol */
+struct TBuf;
+
+/**
+ * Abstract class for a thrift protocol driver. These are all the methods that
+ * a protocol must implement. Essentially, there must be some way of reading
+ * and writing all the base types, plus a mechanism for writing out structs
+ * with indexed fields. Also notice that all methods are strictly const. This
+ * is by design. Protcol impelementations may NOT keep state, because the
+ * same TProtocol object may be used simultaneously by multiple threads. This
+ * theoretically introduces some limititations into the possible protocol
+ * formats, but with the benefit of performance, clarity, and simplicity.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TProtocol {
+ public:
+  virtual ~TProtocol() {}
+
+  /**
+   * Function call serialization.
+   */
+
+  virtual std::string
+    readFunction(TBuf& buf) const = 0;
+  virtual std::string
+    writeFunction(const std::string& name, const std::string& args) const = 0;
+
+  /**
+   * Struct serialization.
+   */
+
+  virtual std::map<uint32_t, TBuf>
+    readStruct(TBuf& buf) const = 0;
+  virtual std::string
+    writeStruct(const std::map<uint32_t,std::string>& s) const = 0;
+
+  /**
+   * Basic data type deserialization. Note that these read methods do not
+   * take a const reference to the TBuf object. They SHOULD change the TBuf
+   * object so that it reflects the buffer AFTER the basic data type has
+   * been consumed such that data may continue being read serially from the
+   * buffer.
+   */
+
+  virtual std::string readString  (TBuf& buf) const = 0;
+  virtual uint8_t     readByte    (TBuf& buf) const = 0;
+  virtual uint32_t    readU32     (TBuf& buf) const = 0;
+  virtual int32_t     readI32     (TBuf& buf) const = 0;
+  virtual uint64_t    readU64     (TBuf& buf) const = 0;
+  virtual int64_t     readI64     (TBuf& buf) const = 0;
+
+  virtual std::string writeString (const std::string& str) const = 0;
+  virtual std::string writeByte   (const uint8_t  byte)    const = 0;
+  virtual std::string writeU32    (const uint32_t u32)     const = 0;
+  virtual std::string writeI32    (const int32_t  i32)     const = 0;
+  virtual std::string writeU64    (const uint64_t u64)     const = 0;
+  virtual std::string writeI64    (const int64_t  i64)     const = 0;
+
+ protected:
+  TProtocol() {}
+};
+
+/**
+ * Wrapper around raw data that allows us to track the length of a data
+ * buffer. It is the responsibility of a robust TProtocol implementation
+ * to ensure that any reads that are done from data do NOT overrun the
+ * memory address at data+len. It is also a convention that TBuf objects
+ * do NOT own the memory pointed to by data. They are merely wrappers
+ * around buffers that have been allocated elsewhere. Therefore, the user
+ * should never allocate memory before putting it into a TBuf nor should
+ * they free the data pointed to by a TBuf.
+ */
+struct TBuf {
+  TBuf(const TBuf& that) : data(that.data), len(that.len) {}
+  TBuf(const uint8_t* d, uint32_t l) : data(d), len(l) {}
+  const uint8_t* data;
+  uint32_t len;
+};
+
+#endif
diff --git a/lib/cpp/server/TServer.h b/lib/cpp/server/TServer.h
new file mode 100644
index 0000000..9c4cc59
--- /dev/null
+++ b/lib/cpp/server/TServer.h
@@ -0,0 +1,36 @@
+#ifndef T_SERVER_H
+#define T_SERVER_H
+
+#include "TDispatcher.h"
+
+class TServerOptions;
+
+/**
+ * Thrift server.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TServer {
+ public:
+  virtual ~TServer() {}
+  virtual void run() = 0;
+
+ protected:
+  TServer(TDispatcher* dispatcher, TServerOptions* options) :
+    dispatcher_(dispatcher), options_(options) {}
+    
+  TDispatcher* dispatcher_;
+  TServerOptions* options_;
+};
+
+/**
+ * Class to encapsulate all generic server options.
+ */
+class TServerOptions {
+ public:
+  // TODO(mcslee): Fill in getters/setters here
+ protected:
+  // TODO(mcslee): Fill data members in here
+};
+
+#endif
diff --git a/lib/cpp/server/TSimpleServer.cc b/lib/cpp/server/TSimpleServer.cc
new file mode 100644
index 0000000..16f5006
--- /dev/null
+++ b/lib/cpp/server/TSimpleServer.cc
@@ -0,0 +1,60 @@
+#include "server/TSimpleServer.h"
+#include <string>
+using namespace std;
+
+void TSimpleServer::run() {
+  TTransport* client;
+
+  // Start the server listening
+  if (serverTransport_->listen() == false) {
+    // TODO(mcslee): Log error here
+    fprintf(stderr, "TSimpleServer::run(): Call to listen failed\n");
+    return;
+  }
+
+  // Fetch client from server
+  while (true) {
+    // fprintf(stderr, "Listening for connection\n");
+    if ((client = serverTransport_->accept()) == NULL) {
+      // fprintf(stderr, "Got NULL connection, exiting.\n");
+      break;
+    }
+
+    while (true) {
+      // Read header from client
+      // fprintf(stderr, "Reading 4 byte header from client.\n");
+      string in;
+      if (client->read(in, 4) <= 0) {
+        // fprintf(stderr, "Size header negative. Exception!\n");
+        break;
+      }
+      
+      // Read payload from client
+      int32_t size = *(int32_t*)(in.data());
+      // fprintf(stderr, "Reading %d byte payload from client.\n", size);
+      if (client->read(in, size) < size) {
+        // fprintf(stderr, "Didn't get enough data!!!\n");
+        break;
+      }
+      
+      // Pass payload to dispatcher
+      // TODO(mcslee): Wrap this in try/catch and return exceptions
+      string out = dispatcher_->dispatch(in);
+      
+      size = out.size();
+      
+      // Write size of response packet
+      client->write(string((char*)&size, 4));
+      
+      // Write response payload
+      client->write(out);
+    }
+  
+    // Clean up that client
+    // fprintf(stderr, "Closing and cleaning up client\n");
+    client->close();
+    delete client;
+  }
+
+  // TODO(mcslee): Is this a timeout case or the real thing?
+}
diff --git a/lib/cpp/server/TSimpleServer.h b/lib/cpp/server/TSimpleServer.h
new file mode 100644
index 0000000..47ab69e
--- /dev/null
+++ b/lib/cpp/server/TSimpleServer.h
@@ -0,0 +1,30 @@
+#ifndef T_SIMPLE_SERVER_H
+#define T_SIMPLE_SERVER_H
+
+#include "server/TServer.h"
+#include "transport/TServerTransport.h"
+
+/**
+ * This is the most basic simple server. It is single-threaded and runs a
+ * continuous loop of accepting a single connection, processing requests on
+ * that connection until it closes, and then repeating. It is a good example
+ * of how to extend the TServer interface.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TSimpleServer : public TServer {
+ public:
+  TSimpleServer(TDispatcher* dispatcher,
+                TServerOptions* options,
+                TServerTransport* serverTransport) :
+    TServer(dispatcher, options), serverTransport_(serverTransport) {}
+    
+  ~TSimpleServer() {}
+
+  void run();
+
+ protected:
+  TServerTransport* serverTransport_;
+};
+
+#endif
diff --git a/lib/cpp/transport/TServerSocket.cc b/lib/cpp/transport/TServerSocket.cc
new file mode 100644
index 0000000..178de81
--- /dev/null
+++ b/lib/cpp/transport/TServerSocket.cc
@@ -0,0 +1,90 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "transport/TSocket.h"
+#include "transport/TServerSocket.h"
+
+TServerSocket::TServerSocket(int port) :
+  port_(port), serverSocket_(0), acceptBacklog_(1024) {}
+
+TServerSocket::~TServerSocket() {
+  close();
+}
+
+bool TServerSocket::listen() {
+  serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
+  if (serverSocket_ == -1) {
+    close();
+    return false;
+  }
+
+  // Set reusaddress to prevent 2MSL delay on accept
+  int one = 1;
+  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
+                       &one, sizeof(one))) {
+    perror("TServerSocket::listen() SO_REUSEADDR");
+    close();
+    return false;
+  }
+
+  // Turn linger off, don't want to block on calls to close
+  struct linger ling = {0, 0};
+  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
+                       &ling, sizeof(ling))) {
+    perror("TServerSocket::listen() SO_LINGER");
+    close();
+    return false;
+  }
+
+  // Bind to a port
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(port_);
+  addr.sin_addr.s_addr = INADDR_ANY;
+  if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
+    char errbuf[1024];
+    sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
+    perror(errbuf);
+    close();
+    return false;
+  }
+
+  // Call listen
+  if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
+    perror("TServerSocket::listen() LISTEN");
+    close();
+    return false;
+  }
+
+  // The socket is now listening!
+  return true;
+}
+
+TTransport* TServerSocket::accept() {
+  if (serverSocket_ <= 0) {
+    // TODO(mcslee): Log error with common logging tool
+    return NULL;
+  }
+
+  struct sockaddr_in clientAddress;
+  int size = sizeof(clientAddress);
+  int clientSocket = ::accept(serverSocket_,
+                              (struct sockaddr *) &clientAddress,
+                              (socklen_t *) &size);
+    
+  if (clientSocket <= 0) {
+    perror("TServerSocket::accept()");
+    return NULL;
+  }
+
+  return new TSocket(clientSocket);
+}
+
+void TServerSocket::close() {
+  if (serverSocket_ > 0) {
+    shutdown(serverSocket_, SHUT_RDWR);
+    ::close(serverSocket_);
+  }
+  serverSocket_ = 0;
+}
diff --git a/lib/cpp/transport/TServerSocket.h b/lib/cpp/transport/TServerSocket.h
new file mode 100644
index 0000000..8ded4e2
--- /dev/null
+++ b/lib/cpp/transport/TServerSocket.h
@@ -0,0 +1,29 @@
+#ifndef T_SERVER_SOCKET_H
+#define T_SERVER_SOCKET_H
+
+#include "transport/TServerTransport.h"
+
+class TSocket;
+
+/**
+ * Server socket implementation of TServerTransport. Wrapper around a unix
+ * socket listen and accept calls.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TServerSocket : public TServerTransport {
+ public:
+  TServerSocket(int port);
+  ~TServerSocket();
+
+  bool listen();
+  TTransport* accept();
+  void close();
+
+ private:
+  int port_;
+  int serverSocket_;
+  int acceptBacklog_;
+};
+
+#endif
diff --git a/lib/cpp/transport/TServerTransport.h b/lib/cpp/transport/TServerTransport.h
new file mode 100644
index 0000000..4d063fc
--- /dev/null
+++ b/lib/cpp/transport/TServerTransport.h
@@ -0,0 +1,24 @@
+#ifndef T_SERVER_TRANSPORT_H
+#define T_SERVER_TRANSPORT_H
+
+#include "TTransport.h"
+
+/**
+ * Server transport framework. A server needs to have some facility for
+ * creating base transports to read/write from.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TServerTransport {
+ public:
+  virtual ~TServerTransport() {}
+
+  virtual bool listen() = 0;
+  virtual TTransport* accept() = 0;
+  virtual void close() = 0;
+
+ protected:
+  TServerTransport() {}
+};
+
+#endif
diff --git a/lib/cpp/transport/TSocket.cc b/lib/cpp/transport/TSocket.cc
new file mode 100644
index 0000000..1dfe431
--- /dev/null
+++ b/lib/cpp/transport/TSocket.cc
@@ -0,0 +1,180 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "transport/TSocket.h"
+
+using namespace std;
+
+// Mutex to protect syscalls to netdb
+pthread_mutex_t g_netdb_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+// TODO(mcslee): Make this an option to the socket class
+#define MAX_RECV_RETRIES 20
+
+TSocket::TSocket(string host, int port) :
+  host_(host), port_(port), socket_(0) {}
+
+TSocket::TSocket(int socket) {
+  socket_ = socket;
+}
+
+TSocket::~TSocket() {
+  close();
+}
+
+bool TSocket::open() {
+  // Create socket
+  socket_ = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_ == -1) {
+    socket_ = 0;
+    return false;
+  }
+  
+  // Lookup the host
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(port_);
+
+  /*
+  if (inet_pton(AF_INET, host_.c_str(), &addr.sin_addr) < 0) {
+    perror("TSocket::open() inet_pton");
+  }
+  */
+
+  {
+    // TODO(mcslee): Fix scope-locking here to protect hostname lookups
+    // scopelock sl(&netdb_mutex);
+    struct hostent *host_entry = gethostbyname(host_.c_str());
+    
+    if (host_entry == NULL) {
+      // perror("dns error: failed call to gethostbyname.\n");
+      close();
+      return false;
+    }
+    
+    addr.sin_port = htons(port_);
+    memcpy(&addr.sin_addr.s_addr,
+           host_entry->h_addr_list[0],
+           host_entry->h_length);
+  }
+   
+  // Connect the socket
+  int ret = connect(socket_, (struct sockaddr *)&addr, sizeof(addr));
+  
+  // Connect failed
+  if (ret < 0) {
+    perror("TSocket::open() connect");
+    close();
+    return false;
+  }
+
+  return true;
+}
+
+void TSocket::close() {
+  if (socket_ > 0) {
+    shutdown(socket_, SHUT_RDWR);
+    ::close(socket_);
+  }
+  socket_ = 0;
+}
+
+int TSocket::read(string& s, uint32_t len) {
+  char buff[len];
+  s = "";
+
+  uint32_t have = 0;
+  uint32_t retries = 0;
+
+  while (have < len) {
+  try_again:
+    // Read from the socket
+    int got = recv(socket_, buff+have, len-have, 0);
+
+    // Check for error on read
+    if (got < 0) {
+      perror("TSocket::read()");
+
+      // If temporarily out of resources, sleep a bit and try again
+      if (errno == EAGAIN && retries++ < MAX_RECV_RETRIES) {
+        usleep(50);
+        goto try_again;
+      }
+
+      // If interrupted, try again
+      if (errno == EINTR && retries++ < MAX_RECV_RETRIES) {
+        goto try_again;
+      }
+
+      // If we disconnect with no linger time
+      if (errno == ECONNRESET) {
+        return 0;
+      }
+
+      return 0;
+    }
+    
+    // Check for empty read
+    if (got == 0) {
+      return 0;
+    }
+    
+    // Update the count
+    have += (uint32_t) got;
+  }
+  
+  // Pack data into string
+  s = string(buff, have);
+  return have;
+}
+
+void TSocket::write(const string& s) {
+  uint32_t sent = 0;
+    
+  while (sent < s.size()) {
+    int b = send(socket_, s.data() + sent, s.size() - sent, 0);
+    
+    // Fail on a send error
+    if (b < 0) {
+      // TODO(mcslee): Make the function return how many bytes it wrote or
+      // throw an exception
+      // throw_perror("send");
+      return;
+    }
+    
+    // Fail on blocked send
+    if (b == 0) {
+      // TODO(mcslee): Make the function return how many bytes it wrote or
+      // throw string("couldn't send data.\n");
+      return;
+    }
+
+    sent += b;
+  }
+}
+
+bool TSocket::setLinger(bool on, int linger) {
+  struct linger ling = {(on ? 1 : 0), linger};
+  if (-1 == setsockopt(socket_, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling))) {
+    close();
+    perror("TSocket::setLinger()");
+    return false;
+  }
+  return true; 
+}
+
+bool TSocket::setNoDelay(bool noDelay) {
+  // Set socket to NODELAY
+  int val = (noDelay ? 1 : 0);
+  if (-1 == setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) {
+    close();
+    perror("TSocket::setNoDelay()");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/cpp/transport/TSocket.h b/lib/cpp/transport/TSocket.h
new file mode 100644
index 0000000..1da74c6
--- /dev/null
+++ b/lib/cpp/transport/TSocket.h
@@ -0,0 +1,39 @@
+#ifndef T_SOCKET_H
+#define T_SOCKET_H
+
+#include <string>
+
+#include "transport/TTransport.h"
+#include "transport/TServerSocket.h"
+
+class TSocketOptions;
+
+/**
+ * TCP Socket implementation of the TTransport interface.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TSocket : public TTransport {
+  friend TTransport* TServerSocket::accept();
+
+ public:
+  TSocket(std::string host, int port);
+  ~TSocket();
+
+  bool open();
+  void close();
+  int  read (std::string &s, uint32_t size);
+  void write(const std::string& s);
+
+  bool setLinger(bool on, int linger);
+  bool setNoDelay(bool noDelay);
+
+ private:
+  TSocket(int socket);
+  TSocketOptions *options_;
+  std::string host_;
+  int port_;
+  int socket_;
+};
+
+#endif
diff --git a/lib/cpp/transport/TTransport.h b/lib/cpp/transport/TTransport.h
new file mode 100644
index 0000000..a1f43d4
--- /dev/null
+++ b/lib/cpp/transport/TTransport.h
@@ -0,0 +1,25 @@
+#ifndef T_TRANSPORT_H
+#define T_TRANSPORT_H
+
+#include <string>
+
+/**
+ * Generic interface for a method of transporting data.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TTransport {
+ public:
+  virtual ~TTransport() {};
+
+  virtual bool open() = 0;
+  virtual void close() = 0;
+
+  virtual int  read (std::string& s, uint32_t size) = 0;
+  virtual void write(const std::string& s) = 0;
+
+ protected:
+  TTransport() {};
+};
+
+#endif
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
new file mode 100644
index 0000000..6999f4e
--- /dev/null
+++ b/test/ThriftTest.thrift
@@ -0,0 +1,57 @@
+enum Numberz
+{
+  ONE = 1,
+  TWO,
+  THREE,
+  FIVE = 5,
+  SIX,
+  EIGHT = 8
+}
+
+typedef u64 UserId
+
+struct Xtruct
+{
+  string string_thing = 0,
+  byte   byte_thing = 1,
+  u32    u32_thing = 2,
+  i32    i32_thing = 3,
+  u64    u64_thing = 4,
+  i64    i64_thing = 5
+}
+
+struct Xtruct2
+{
+  byte   byte_thing = 0,
+  Xtruct struct_thing = 1,
+  i32    i32_thing = 2
+}
+
+struct Insanity
+{
+  map<Numberz, UserId> userMap = 0,
+  list<Xtruct> xtructs = 1
+}
+
+service ThriftTest
+{
+  void         testVoid()
+  string       testString(string thing = 0)
+  byte         testByte(byte thing = 0)
+  u32          testU32(u32 thing = 0)
+  i32          testI32(i32 thing = 0)
+  u64          testU64(u64 thing = 0)
+  i64          testI64(i64 thing = 0)
+  Xtruct       testStruct(Xtruct thing = 0)
+  Xtruct2      testNest(Xtruct2 thing = 0)
+  map<i32,i32> testMap(map<i32,i32> thing = 0)
+  set<i32>     testSet(set<i32> thing = 0)
+  list<i32>    testList(list<i32> thing = 0)
+  Numberz      testEnum(Numberz thing = 0)
+  UserId       testTypedef(UserId thing = 0)
+
+  map<i32,map<i32,i32>> testMapMap(i32 hello = 0)
+
+  /* So you think you've got this all worked, out eh? */
+  map<UserId, map<Numberz,Insanity>> testInsanity(Insanity argument = 0)
+}
diff --git a/test/cpp/Makefile b/test/cpp/Makefile
new file mode 100644
index 0000000..6afb30b
--- /dev/null
+++ b/test/cpp/Makefile
@@ -0,0 +1,34 @@
+# Makefile for Thrift test project.
+# 
+# Author:
+#   Mark Slee <mcslee@facebook.com>
+
+# Default target is everything
+target: all
+
+# Tools
+THRIFT = /usr/local/bin/thrift
+CC     = g++
+LD     = g++
+
+# Compiler flags
+LIBS  = ../../lib/cpp/server/TSimpleServer.cc \
+	../../lib/cpp/protocol/TBinaryProtocol.cc \
+	../../lib/cpp/transport/TServerSocket.cc \
+	../../lib/cpp/transport/TSocket.cc
+CFL   = -Wall -g -I../../lib/cpp $(LIBS)
+CFL   = -Wall -g -lthrift -I../../lib/cpp
+
+all: server client
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) ../ThriftTest.thrift
+
+server: stubs
+	g++ -o TestServer $(CFL) TestServer.cc gen-cpp/ThriftTest.cc
+
+client: stubs
+	g++ -o TestClient $(CFL) TestClient.cc gen-cpp/ThriftTest.cc
+
+clean:
+	rm -fr TestServer TestClient gen-cpp
diff --git a/test/cpp/TestClient.cc b/test/cpp/TestClient.cc
new file mode 100644
index 0000000..6d2a68e
--- /dev/null
+++ b/test/cpp/TestClient.cc
@@ -0,0 +1,327 @@
+#include <stdio.h>
+#include <unistd.h>
+#include "protocol/TBinaryProtocol.h"
+#include "client/TSimpleClient.h"
+#include "transport/TSocket.h"
+#include "gen-cpp/ThriftTest.h"
+using namespace std;
+
+int main(int argc, char** argv) {
+  string host = "localhost";
+  int port = 9090;
+  int numTests = 1;
+
+  if (argc > 1) {
+    host = argv[1];
+  }
+  if (argc > 2) {
+    port = atoi(argv[2]);
+  }
+  if (argc > 3) {
+    numTests = atoi(argv[3]);
+  }
+
+  TSocket socket(host, port);
+  TSimpleClient simpleClient(&socket);
+  TBinaryProtocol binaryProtocol;
+  ThriftTestClient testClient(&simpleClient, &binaryProtocol);
+  
+  int test = 0;
+  for (test = 0; test < numTests; ++test) {
+    printf("Test #%d, connect %s:%d\n", test+1, host.c_str(), port);
+    bool success = simpleClient.open();
+    if (!success) {
+      printf("Connect failed, server down?\n");
+      continue;
+    }
+    
+    /**
+     * VOID TEST
+     */
+    printf("testVoid()");
+    testClient.testVoid();
+    printf(" = void\n");
+    
+    /**
+     * STRING TEST
+     */
+    printf("testString(\"Test\")");
+    string s = testClient.testString("Test");
+    printf(" = \"%s\"\n", s.c_str());
+   
+    /**
+     * BYTE TEST
+     */
+    printf("testByte(1)");
+    uint8_t u8 = testClient.testByte(1);
+    printf(" = %d\n", (int)u8);
+
+    /**
+     * U32 TEST
+     */
+    printf("testU32(1)");
+    uint32_t u32 = testClient.testU32(1);
+    printf(" = %u\n", u32);
+    
+    /**
+     * I32 TEST
+     */
+    printf("testI32(-1)");
+    int32_t i32 = testClient.testI32(-1);
+    printf(" = %d\n", i32);
+
+    /**
+     * U64 TEST
+     */
+    printf("testU64(34359738368)");
+    uint64_t u64 = testClient.testU64(34359738368);
+    printf(" = %lu\n", u64);
+
+    /**
+     * I64 TEST
+     */
+    printf("testI64(-34359738368)");
+    int64_t i64 = testClient.testI64(-34359738368);
+    printf(" = %ld\n", i64);
+    
+    /**
+     * STRUCT TEST
+     */
+    printf("testStruct({\"Zero\", 1, 2, -3, 4, -5})");
+    Xtruct out;
+    out.string_thing = "Zero";
+    out.byte_thing = 1;
+    out.u32_thing = 2;
+    out.i32_thing = -3;
+    out.u64_thing = 4;
+    out.i64_thing = -5;
+    Xtruct in = testClient.testStruct(out);
+    printf(" = {\"%s\", %d, %u, %d, %lu, %ld}\n",
+           in.string_thing.c_str(),
+           (int)in.byte_thing,
+           in.u32_thing,
+           in.i32_thing,
+           in.u64_thing,
+           in.i64_thing);
+    
+    /**
+     * NESTED STRUCT TEST
+     */
+    printf("testNest({1, {\"Zero\", 1, 2, -3, 4, -5}), 5}");
+    Xtruct2 out2;
+    out2.byte_thing = 1;
+    out2.struct_thing = out;
+    out2.i32_thing = 5;
+    Xtruct2 in2 = testClient.testNest(out2);
+    in = in2.struct_thing;
+    printf(" = {%d, {\"%s\", %d, %u, %d, %lu, %ld}, %d}\n",
+           in2.byte_thing,
+           in.string_thing.c_str(),
+           (int)in.byte_thing,
+           in.u32_thing,
+           in.i32_thing,
+           in.u64_thing,
+           in.i64_thing,
+           in2.i32_thing);   
+
+    /**
+     * MAP TEST
+     */
+    map<int32_t,int32_t> mapout;
+    for (int32_t i = 0; i < 5; ++i) {
+      mapout.insert(make_pair(i, i-10));
+    }
+    printf("testMap({");
+    map<int32_t, int32_t>::const_iterator m_iter;
+    bool first = true;
+    for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("})");
+    map<int32_t,int32_t> mapin = testClient.testMap(mapout);
+    printf(" = {");
+    first = true;
+    for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("}\n");
+
+    /**
+     * SET TEST
+     */
+    set<int32_t> setout;
+    for (int32_t i = -2; i < 3; ++i) {
+      setout.insert(i);
+    }
+    printf("testSet({");
+    set<int32_t>::const_iterator s_iter;
+    first = true;
+    for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("})");
+    set<int32_t> setin = testClient.testSet(setout);
+    printf(" = {");
+    first = true;
+    for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("}\n");
+
+    /**
+     * LIST TEST
+     */
+    list<int32_t> listout;
+    for (int32_t i = -2; i < 3; ++i) {
+      listout.push_back(i);
+    }
+    printf("testList({");
+    list<int32_t>::const_iterator l_iter;
+    first = true;
+    for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("})");
+    list<int32_t> listin = testClient.testList(listout);
+    printf(" = {");
+    first = true;
+    for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("}\n");
+
+    /**
+     * ENUM TEST
+     */
+    printf("testEnum(ONE)");
+    Numberz ret = testClient.testEnum(ONE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(TWO)");
+    ret = testClient.testEnum(TWO);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(THREE)");
+    ret = testClient.testEnum(THREE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(FIVE)");
+    ret = testClient.testEnum(FIVE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(EIGHT)");
+    ret = testClient.testEnum(EIGHT);
+    printf(" = %d\n", ret);
+
+    /**
+     * TYPEDEF TEST
+     */
+    printf("testTypedef(309858235082523)");
+    UserId uid = testClient.testTypedef(309858235082523);
+    printf(" = %lu\n", uid);
+
+    /**
+     * NESTED MAP TEST
+     */
+    printf("testMapMap(1)");
+    map<int32_t, map<int32_t, int32_t> > mm = testClient.testMapMap(1);
+    printf(" = {");
+    map<int32_t, map<int32_t, int32_t> >::const_iterator mi;
+    for (mi = mm.begin(); mi != mm.end(); ++mi) {
+      printf("%d => {", mi->first);
+      map<int32_t, int32_t>::const_iterator mi2;
+      for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) {
+        printf("%d => %d, ", mi2->first, mi2->second);
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+    /**
+     * INSANITY TEST
+     */
+    Insanity insane;
+    insane.userMap.insert(make_pair(FIVE, 5000));
+    Xtruct truck;
+    truck.string_thing = "Truck";
+    truck.byte_thing = 8;
+    truck.u32_thing = 8;
+    truck.i32_thing = 8;
+    truck.u64_thing = 8;
+    truck.i64_thing = 8;
+    insane.xtructs.push_back(truck);
+    printf("testInsanity()");
+    map<UserId, map<Numberz,Insanity> > whoa = testClient.testInsanity(insane);
+    printf(" = {");
+    map<UserId, map<Numberz,Insanity> >::const_iterator i_iter;
+    for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) {
+      printf("%lu => {", i_iter->first);
+      map<Numberz,Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin();
+           i2_iter != i_iter->second.end();
+           ++i2_iter) {
+        printf("%d => {", i2_iter->first);
+        map<Numberz, UserId> userMap = i2_iter->second.userMap;
+        map<Numberz, UserId>::const_iterator um;
+        printf("{");
+        for (um = userMap.begin(); um != userMap.end(); ++um) {
+          printf("%d => %lu, ", um->first, um->second);
+        }
+        printf("}, ");
+
+        list<Xtruct> xtructs = i2_iter->second.xtructs;
+        list<Xtruct>::const_iterator x;
+        printf("{");
+        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+          printf("{\"%s\", %d, %u, %d, %lu, %ld}, ",
+                 x->string_thing.c_str(),
+                 (int)x->byte_thing,
+                 x->u32_thing,
+                 x->i32_thing,
+                 x->u64_thing,
+                 x->i64_thing);
+        }
+        printf("}");
+
+        printf("}, ");
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+    simpleClient.close();
+  }
+
+  printf("\nAll tests done.\n");
+  return 0;
+}
diff --git a/test/cpp/TestServer.cc b/test/cpp/TestServer.cc
new file mode 100644
index 0000000..8138166
--- /dev/null
+++ b/test/cpp/TestServer.cc
@@ -0,0 +1,254 @@
+#include <stdio.h>
+#include "protocol/TBinaryProtocol.h"
+#include "server/TSimpleServer.h"
+#include "transport/TServerSocket.h"
+#include "gen-cpp/ThriftTest.h"
+using namespace std;
+
+class TestServer : public ThriftTestServerIf {
+ public:
+  TestServer(TProtocol* protocol) :
+    ThriftTestServerIf(protocol) {}
+
+  void testVoid() {
+    printf("testVoid()\n");
+  }
+
+  string testString(string thing) {
+    printf("testString(\"%s\")\n", thing.c_str());
+    return thing;
+  }
+
+  uint8_t testByte(uint8_t thing) {
+    printf("testByte(%d)\n", (int)thing);
+    return thing;
+  }
+
+  uint32_t testU32(uint32_t thing) {
+    printf("testU32(%u)\n", thing);
+    return thing;
+  }
+
+  int32_t testI32(int32_t thing) {
+    printf("testI32(%d)\n", thing);
+    return thing;
+  }
+
+  uint64_t testU64(uint64_t thing) {
+    printf("testU64(%lu)\n", thing);
+    return thing;
+  }
+
+  int64_t testI64(int64_t thing) {
+    printf("testI64(%ld)\n", thing);
+    return thing;
+  }
+
+  Xtruct testStruct(Xtruct thing) {
+    printf("testStruct({\"%s\", %d, %u, %d, %lu, %ld})\n",
+           thing.string_thing.c_str(),
+           (int)thing.byte_thing,
+           thing.u32_thing,
+           thing.i32_thing,
+           thing.u64_thing,
+           thing.i64_thing);
+    return thing;
+  }
+
+  Xtruct2 testNest(Xtruct2 nest) {
+    Xtruct thing = nest.struct_thing;
+    printf("testNest({%d, {\"%s\", %d, %u, %d, %lu, %ld}, %d})\n",
+           (int)nest.byte_thing,
+           thing.string_thing.c_str(),
+           (int)thing.byte_thing,
+           thing.u32_thing,
+           thing.i32_thing,
+           thing.u64_thing,
+           thing.i64_thing,
+           nest.i32_thing);
+    return nest;
+  }
+
+  map<int32_t, int32_t> testMap(map<int32_t, int32_t> thing) {
+    printf("testMap({");
+    map<int32_t, int32_t>::const_iterator m_iter;
+    bool first = true;
+    for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("})\n");
+    return thing;
+  }
+
+  set<int32_t> testSet(set<int32_t> thing) {
+    printf("testSet({");
+    set<int32_t>::const_iterator s_iter;
+    bool first = true;
+    for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("})\n");
+    return thing;
+  }
+
+  list<int32_t> testList(list<int32_t> thing) {
+    printf("testList({");
+    list<int32_t>::const_iterator l_iter;
+    bool first = true;
+    for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("})\n");
+    return thing;
+  }
+
+  Numberz testEnum(Numberz thing = 0) {
+    printf("testEnum(%d)\n", thing);
+    return thing;
+  }
+
+  UserId testTypedef(UserId thing = 0) {
+    printf("testTypedef(%lu)\n", thing);
+    return thing;
+  }
+
+  map<int32_t, map<int32_t,int32_t> > testMapMap(int32_t hello) {
+    printf("testMapMap(%d)\n", hello);
+    map<int32_t, map<int32_t,int32_t> > mapmap;
+
+    map<int32_t,int32_t> pos;
+    map<int32_t,int32_t> neg;
+    for (int i = 1; i < 5; i++) {
+      pos.insert(make_pair(i,i));
+      neg.insert(make_pair(-i,-i));
+    }
+
+    mapmap.insert(make_pair(4, pos));
+    mapmap.insert(make_pair(-4, neg));
+
+    return mapmap;
+  }
+
+  map<UserId, map<Numberz,Insanity> > testInsanity(Insanity argument) {
+    printf("testInsanity()\n");
+    
+    Xtruct hello;
+    hello.string_thing = "Hello2";
+    hello.byte_thing = 2;
+    hello.u32_thing = 2;
+    hello.i32_thing = 2;
+    hello.u64_thing = 2;
+    hello.i64_thing = 2;
+
+    Xtruct goodbye;
+    goodbye.string_thing = "Goodbye4";
+    goodbye.byte_thing = 4;
+    goodbye.u32_thing = 4;
+    goodbye.i32_thing = 4;
+    goodbye.u64_thing = 4;
+    goodbye.i64_thing = 4;
+
+    Insanity crazy;
+    crazy.userMap.insert(make_pair(EIGHT, 8));
+    crazy.xtructs.push_back(goodbye);
+
+    Insanity looney;
+    crazy.userMap.insert(make_pair(FIVE, 5));
+    crazy.xtructs.push_back(hello);
+
+    map<Numberz, Insanity> first_map;
+    map<Numberz, Insanity> second_map;
+
+    first_map.insert(make_pair(TWO, crazy));
+    first_map.insert(make_pair(THREE, crazy));
+
+    second_map.insert(make_pair(SIX, looney));
+
+    map<UserId, map<Numberz,Insanity> > insane;
+    insane.insert(make_pair(1, first_map));
+    insane.insert(make_pair(2, second_map));
+
+    printf("return");
+    printf(" = {");
+    map<UserId, map<Numberz,Insanity> >::const_iterator i_iter;
+    for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
+      printf("%lu => {", i_iter->first);
+      map<Numberz,Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin();
+           i2_iter != i_iter->second.end();
+           ++i2_iter) {
+        printf("%d => {", i2_iter->first);
+        map<Numberz, UserId> userMap = i2_iter->second.userMap;
+        map<Numberz, UserId>::const_iterator um;
+        printf("{");
+        for (um = userMap.begin(); um != userMap.end(); ++um) {
+          printf("%d => %lu, ", um->first, um->second);
+        }
+        printf("}, ");
+
+        list<Xtruct> xtructs = i2_iter->second.xtructs;
+        list<Xtruct>::const_iterator x;
+        printf("{");
+        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+          printf("{\"%s\", %d, %u, %d, %lu, %ld}, ",
+                 x->string_thing.c_str(),
+                 (int)x->byte_thing,
+                 x->u32_thing,
+                 x->i32_thing,
+                 x->u64_thing,
+                 x->i64_thing);
+        }
+        printf("}");
+
+        printf("}, ");
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+    return insane;
+  }
+
+};
+
+int main(int argc, char **argv) {
+  int port = 9090;
+  if (argc > 1) {
+    port = atoi(argv[1]);
+  }
+ 
+  // Dispatcher
+  TBinaryProtocol binaryProtocol;
+  TestServer testServer(&binaryProtocol);
+
+  // Options
+  TServerOptions serverOptions;
+
+  // Transport
+  TServerSocket serverSocket(port);
+
+  // Server
+  TSimpleServer simpleServer(&testServer,
+                             &serverOptions,
+                             &serverSocket);
+
+  printf("Starting the server on port %d...\n", port);
+  simpleServer.run();
+  printf("done.\n");
+  return 0;
+}