Thrift: C# Bindings.
authorDavid Reiss <dreiss@apache.org>
Fri, 11 Jan 2008 20:59:12 +0000 (20:59 +0000)
committerDavid Reiss <dreiss@apache.org>
Fri, 11 Jan 2008 20:59:12 +0000 (20:59 +0000)
Summary:
C# generator, library, and MS Build task contributed by imeem.

Reviewed By: mcslee

Test Plan:
Built the Thrift compiler and generated some C# code.
I'd love to say I installed Mono or Portable.NET and built the C# code,
but I did not.

Revert Plan: ok

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665421 13f79535-47bb-0310-9956-ffa450edef68

41 files changed:
CONTRIBUTORS
compiler/cpp/Makefile.am
compiler/cpp/src/generate/t_csharp_generator.cc [new file with mode: 0644]
compiler/cpp/src/generate/t_csharp_generator.h [new file with mode: 0644]
compiler/cpp/src/main.cc
compiler/cpp/src/parse/t_program.h
compiler/cpp/src/thriftl.ll
compiler/cpp/src/thrifty.yy
lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs [new file with mode: 0644]
lib/csharp/ThriftMSBuildTask/ThriftBuild.cs [new file with mode: 0644]
lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj [new file with mode: 0644]
lib/csharp/src/Protocol/TBinaryProtocol.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TField.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TList.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TMap.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TMessage.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TMessageType.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TProtocol.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TProtocolException.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TProtocolFactory.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TProtocolUtil.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TSet.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TStruct.cs [new file with mode: 0644]
lib/csharp/src/Protocol/TType.cs [new file with mode: 0644]
lib/csharp/src/Server/TServer.cs [new file with mode: 0644]
lib/csharp/src/Server/TSimpleServer.cs [new file with mode: 0644]
lib/csharp/src/Server/TThreadPoolServer.cs [new file with mode: 0644]
lib/csharp/src/TApplicationException.cs [new file with mode: 0644]
lib/csharp/src/TProcessor.cs [new file with mode: 0644]
lib/csharp/src/Thrift.csproj [new file with mode: 0644]
lib/csharp/src/Thrift.sln [new file with mode: 0644]
lib/csharp/src/Transport/TServerSocket.cs [new file with mode: 0644]
lib/csharp/src/Transport/TServerTransport.cs [new file with mode: 0644]
lib/csharp/src/Transport/TSocket.cs [new file with mode: 0644]
lib/csharp/src/Transport/TStreamTransport.cs [new file with mode: 0644]
lib/csharp/src/Transport/TTransport.cs [new file with mode: 0644]
lib/csharp/src/Transport/TTransportException.cs [new file with mode: 0644]
lib/csharp/src/Transport/TTransportFactory.cs [new file with mode: 0644]
test/ThriftTest.thrift
thrift.el
thrift.vim

index 5134598..c491c4c 100644 (file)
@@ -13,6 +13,8 @@ Igor Afanasyev <afan@evernote.com>
 
 Todd Berman <tberman@imeem.com>
 - MinGW port of the compiler.
+- C# bindings.
+- MS build task.
 
 ----------------
 Release 20070917
index 2c0368c..3ccef42 100644 (file)
@@ -21,6 +21,7 @@ thrift_SOURCES = src/thrifty.yy \
                  src/generate/t_hs_generator.cc \
                  src/generate/t_cocoa_generator.cc \
                  src/generate/t_st_generator.cc \
+                 src/generate/t_csharp_generator.cc \
                  src/globals.h \
                  src/main.h \
                  src/platform.h \
@@ -56,7 +57,8 @@ thrift_SOURCES = src/thrifty.yy \
                  src/generate/t_erl_generator.h \
                  src/generate/t_hs_generator.h \
                  src/generate/t_cocoa_generator.h \
-                 src/generate/t_st_generator.h
+                 src/generate/t_st_generator.h \
+                 src/generate/t_csharp_generator.h
 
 thrift_CXXFLAGS = -Wall -I$(srcdir)/src $(BOOST_CPPFLAGS)
 thrift_LDFLAGS = -Wall $(BOOST_LDFLAGS)
diff --git a/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc
new file mode 100644 (file)
index 0000000..0ec3e66
--- /dev/null
@@ -0,0 +1,1526 @@
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_csharp_generator.h"
+#include "../platform.h"
+
+using namespace std;
+
+void t_csharp_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  namespace_name_ = program_->get_csharp_namespace();
+
+  string dir = namespace_name_;
+  string subdir = get_out_dir().c_str();
+  string::size_type loc;
+
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  namespace_dir_ = subdir;
+}
+
+void t_csharp_generator::start_csharp_namespace(ofstream& out) {
+  if (!namespace_name_.empty()) {
+    out <<
+      "namespace " << namespace_name_ << "\n";
+    scope_up(out);
+  }
+}
+
+void t_csharp_generator::end_csharp_namespace(ofstream& out) {
+  if (!namespace_name_.empty()) {
+    scope_down(out);
+  }
+}
+
+string t_csharp_generator::csharp_type_usings() {
+  return string() +
+    "using System;\n" +
+    "using System.Collections;\n" + 
+    "using System.Collections.Generic;\n" +
+    "using System.Text;\n" + 
+    "using Thrift;\n";
+}
+
+string t_csharp_generator::csharp_thrift_usings() {
+  return string() +
+    "using Thrift.Protocol;\n" +
+    "using Thrift.Transport;\n";
+}
+
+void t_csharp_generator::close_generator() { }
+void t_csharp_generator::generate_typedef(t_typedef* ttypedef) {}
+
+void t_csharp_generator::generate_enum(t_enum* tenum) {
+  string f_enum_name = namespace_dir_+"/" + (tenum->get_name())+".cs";
+  ofstream f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  f_enum <<
+    autogen_comment() << endl;
+
+  start_csharp_namespace(f_enum);
+
+  indent(f_enum) <<
+    "public enum " << tenum->get_name() << "\n";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  int value = -1;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter)
+  {
+    if ((*c_iter)->has_value()) {
+      value = (*c_iter)->get_value();
+    } else {
+      ++value;
+    }
+
+    indent(f_enum) <<
+      (*c_iter)->get_name() <<
+      " = " << value << "," << endl;
+  }
+
+  scope_down(f_enum);
+  
+  end_csharp_namespace(f_enum);
+
+  f_enum.close();
+}
+
+void t_csharp_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()){
+    return;
+  }
+  string f_consts_name = namespace_dir_ + "/Constants.cs";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  f_consts <<
+    autogen_comment() <<
+    csharp_type_usings() << endl;
+
+  start_csharp_namespace(f_consts);
+
+  indent(f_consts) <<
+    "public class Constants" << endl;
+  scope_up(f_consts);
+
+  vector<t_const*>::iterator c_iter;
+  bool need_static_constructor = false;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if (print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false)) {
+      need_static_constructor = true;
+    }
+  }
+
+  if (need_static_constructor) {
+    print_const_constructor(f_consts, consts);
+  }
+
+  scope_down(f_consts);
+  end_csharp_namespace(f_consts);
+  f_consts.close();
+}
+
+void t_csharp_generator::print_const_def_value(std::ofstream& out, string name, t_type* type, t_const_value* value)
+{
+  if (type->is_struct() || type->is_xception()) {
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
+    }
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "]" << " = " << val << ";" << endl;
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".Add(" << val << ");" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::print_const_constructor(std::ofstream& out, std::vector<t_const*> consts) {
+  indent(out) << "static Constants()" << endl;
+  scope_up(out);
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    t_const_value* value = (*c_iter)->get_value();
+
+    print_const_def_value(out, name, type, value);
+  }
+  scope_down(out);
+}
+
+
+//it seems like all that methods that call this are using in_static to be the opposite of what it would imply
+bool t_csharp_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype) {
+  indent(out);
+  bool need_static_construction = !in_static;
+  if (!defval || needtype) {
+    out <<
+      (in_static ? "" : "public static ") <<
+      type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_enum()) {
+    out << name << " = (" << type_name(type, false, true) << ")" << value->get_integer() << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_struct() || type->is_xception()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, true, true) << "();" << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  }
+
+  if (defval && !type->is_base_type() && !type->is_enum()) {
+    print_const_def_value(out, name, type, value);
+  }
+
+  return need_static_construction;
+}
+
+std::string t_csharp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  std::ostringstream render;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+      case t_base_type::TYPE_STRING:
+        render << "\"" + value->get_string() + "\"";
+        break;
+      case t_base_type::TYPE_BOOL:
+        render << ((value->get_integer() > 0) ? "true" : "false");
+        break;
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        render << value->get_integer();
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        if (value->get_type() == t_const_value::CV_INTEGER) {
+          render << value->get_integer();
+        } else {
+          render << value->get_double();
+        }
+        break;
+      default:
+        throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    render << "(" << type->get_name() << ")" << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true, true, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_csharp_generator::generate_struct(t_struct* tstruct) {
+  generate_csharp_struct(tstruct, false);
+}
+
+void t_csharp_generator::generate_xception(t_struct* txception) {
+  generate_csharp_struct(txception, true);
+}
+
+void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) {
+  string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
+  ofstream f_struct;
+
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct <<
+    autogen_comment() <<
+    csharp_type_usings() <<
+    csharp_thrift_usings();
+
+  generate_csharp_struct_definition(f_struct, tstruct, is_exception);
+
+  f_struct.close();
+}
+
+void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) {
+
+  if (!in_class)
+  {
+    start_csharp_namespace(out);
+  }
+
+  indent(out) <<
+    "public class " << tstruct->get_name() << " ";
+
+  if (is_exception) {
+    out << ": Exception ";
+  }
+
+  out << endl;
+
+  scope_up(out);
+
+  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) {
+    indent(out) <<
+      "public " << declare_field(*m_iter, false) << endl;
+  }
+
+  if (members.size() > 0) {
+    out <<
+      endl <<
+      indent() << "public Isset __isset = new Isset();" << endl <<
+      indent() << "public sealed class Isset {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      indent(out) <<
+        "public bool " << (*m_iter)->get_name() << " = false;" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+  
+  indent(out) <<
+    "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  generate_csharp_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_csharp_struct_result_writer(out, tstruct);
+  } else {
+    generate_csharp_struct_writer(out, tstruct);
+  }
+  generate_csharp_struct_tostring(out, tstruct);
+  scope_down(out);
+  out << endl;
+
+  if (!in_class)
+  {
+    end_csharp_namespace(out);
+  }
+}
+
+void t_csharp_generator::generate_csharp_struct_reader(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public void Read (TProtocol iprot)" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TField field;" << endl <<
+    indent() << "TStruct struc = iprot.ReadStructBegin();" << endl;
+  
+  indent(out) <<
+    "while (true)" << endl;
+  scope_up(out);
+
+  indent(out) <<
+    "field = iprot.ReadFieldBegin();" << endl;
+
+  indent(out) <<
+    "if (field.Type == TType.Stop) { " << endl;
+  indent_up();
+  indent(out) <<
+    "break;" << endl;
+  indent_down();
+  indent(out) <<
+    "}" << endl;
+
+  indent(out) <<
+    "switch (field.ID)" << endl;
+
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) <<
+      "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) <<
+      "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    indent(out) <<
+      "this.__isset." << (*f_iter)->get_name() << " = true;" << endl;
+    indent_down();
+    out <<
+      indent() << "} else { " << endl <<
+      indent() << "  TProtocolUtil.Skip(iprot, field.Type);" << endl <<
+      indent() << "}" << endl <<
+      indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) <<
+    "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) <<
+    "iprot.ReadFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) <<
+    "iprot.ReadStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+
+}
+
+void t_csharp_generator::generate_csharp_struct_writer(ofstream& out, t_struct* tstruct) {
+  out <<
+    indent() << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) <<
+    "TField field = new TField();" << endl;
+  indent(out) <<
+    "oprot.WriteStructBegin(struc);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      indent(out) <<
+        "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+
+    indent(out) <<
+      "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+    indent(out) <<
+      "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+    indent(out) <<
+      "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+    indent(out) <<
+      "oprot.WriteFieldBegin(field);" << endl;
+
+    generate_serialize_field(out, *f_iter, "this.");
+
+    indent(out) <<
+      "oprot.WriteFieldEnd();" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent(out) <<
+    "oprot.WriteFieldStop();" << endl;
+  indent(out) <<
+    "oprot.WriteStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_result_writer(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) <<
+    "TField field = new TField();" << endl;
+  indent(out) <<
+    "oprot.WriteStructBegin(struc);" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out <<
+        endl << indent() << "if ";
+    } else {
+      out <<
+        " else if ";
+    }
+
+    out <<
+      "(this.__isset." << (*f_iter)->get_name() << ") {" << endl;
+    indent_up();
+
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      indent(out) <<
+        "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+
+    indent(out) <<
+      "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+    indent(out) <<
+      "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+    indent(out) <<
+      "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+    indent(out) <<
+      "oprot.WriteFieldBegin(field);" << endl;
+
+    generate_serialize_field(out, *f_iter, "this.");
+
+    indent(out) <<
+      "oprot.WriteFieldEnd();" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}";
+  }
+
+  out <<
+    endl <<
+    indent() << "oprot.WriteFieldStop();" << endl <<
+    indent() << "oprot.WriteStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_tostring(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public override string ToString() {" << endl;
+  indent_up();
+
+  indent(out) <<
+    "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
+
+  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) {
+      first = false;
+      indent(out) <<
+        "sb.Append(\"" << (*f_iter)->get_name() << ": \");" << endl;
+    } else {
+      indent(out) <<
+        "sb.Append(\"," << (*f_iter)->get_name() << ": \");" << endl;
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_xception() || ttype->is_struct()) {
+      indent(out) <<
+        "sb.Append(this." << (*f_iter)->get_name() << ".ToString());" << endl;
+    } else {
+      indent(out) <<
+        "sb.Append(this." << (*f_iter)->get_name() << ");" << endl;
+    }
+  }
+
+  indent(out) <<
+    "sb.Append(\")\");" << endl;
+  indent(out) <<
+    "return sb.ToString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service(t_service* tservice) {
+  string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    autogen_comment() <<
+    csharp_type_usings() <<
+    csharp_thrift_usings();
+
+  start_csharp_namespace(f_service_);
+
+  indent(f_service_) <<
+    "public class " << service_name_ << " {" << endl;
+  indent_up();
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+
+  indent(f_service_) <<
+    "}" << endl;
+  end_csharp_namespace(f_service_);
+  f_service_.close();
+}
+
+void t_csharp_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".Iface";
+  }
+
+  indent(f_service_) <<
+    "public interface Iface" << extends_iface << " {" << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+  {
+    indent(f_service_) <<
+      function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_csharp_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+void t_csharp_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + ".Client, ";
+  }
+
+  indent(f_service_) <<
+    "public class Client : " << extends_client << "Iface {" << endl;
+  indent_up();
+  indent(f_service_) <<
+    "public Client(TProtocol prot) : this(prot, prot)" << endl;
+  scope_up(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public Client(TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "iprot_ = iprot;" << endl <<
+      indent() << "oprot_ = oprot;" << endl;
+  } else {
+    f_service_ <<
+      indent() << "base(iprot, oprot);" << endl;
+  }
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected TProtocol iprot_;" << endl <<
+      indent() << "protected TProtocol oprot_;" << endl <<
+      endl <<
+      indent() << "protected int seqid_;" << endl << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    indent(f_service_) <<
+      "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_async()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    t_function send_function(g_type_void,
+        string("send_") + (*f_iter)->get_name(),
+        (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+
+    indent(f_service_) <<
+      "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ <<
+      indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", TMessageType.Call, seqid_));" << endl <<
+      indent() << argsname << " args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ <<
+      indent() << "args.Write(oprot_);" << endl <<
+      indent() << "oprot_.WriteMessageEnd();" << endl <<
+      indent() << "oprot_.Transport.Flush();" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_async()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+          string("recv_") + (*f_iter)->get_name(),
+          &noargs,
+          (*f_iter)->get_xceptions());
+      indent(f_service_) <<
+        "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ <<
+        indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl <<
+        indent() << "if (msg.Type == TMessageType.Exception) {" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "TApplicationException x = TApplicationException.Read(iprot_);" << endl <<
+        indent() << "iprot_.ReadMessageEnd();" << endl <<
+        indent() << "throw x;" << endl;
+      indent_down();
+      f_service_ <<
+        indent() << "}" << endl <<
+        indent() << resultname << " result = new " << resultname << "();" << endl <<
+        indent() << "result.Read(iprot_);" << endl <<
+        indent() << "iprot_.ReadMessageEnd();" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "if (result.__isset.success) {" << endl <<
+          indent() << "  return result.success;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct *xs = (*f_iter)->get_xceptions();
+
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
+          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "}" << endl;
+      }
+
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return;" << endl;
+      } else {
+        f_service_ <<
+          indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl;
+}
+
+void t_csharp_generator::generate_service_server(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  indent(f_service_) <<
+    "public class Processor : " << extends_processor << "TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public Processor(Iface iface)" << endl;
+  scope_up(f_service_);
+  if (!extends.empty()) {
+    f_service_ <<
+      indent() << "base(iface);" << endl;
+  }
+  f_service_ <<
+    indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = new " << (*f_iter)->get_name() << "();" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected interface ProcessFunction {" << endl <<
+      indent() << "  void Process(int seqid, Iface iface, TProtocol iprot, TProtocol oprot);" << endl <<
+      indent() << "}" << endl << endl;
+  }
+
+  f_service_ <<
+    indent() << "private Iface iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  f_service_ <<
+    indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_ <<
+    indent() << "ProcessFunction fn = processMap_[msg.Name];" << endl <<
+    indent() << "if (fn == null) {" << endl <<
+    indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl <<
+    indent() << "  iprot.ReadMessageEnd();" << endl <<
+    indent() << "  TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl <<
+    indent() << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));" << endl <<
+    indent() << "  x.Write(oprot);" << endl <<
+    indent() << "  oprot.WriteMessageEnd();" << endl <<
+    indent() << "  oprot.Transport.Flush();" << endl <<
+    indent() << "  return true;" << endl <<
+    indent() << "}" << endl <<
+    indent() << "fn.Process(msg.SeqID, iface_, iprot, oprot);" << endl;
+
+  f_service_ <<
+    indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+  {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_async()) {
+    return;
+  }
+
+  t_struct result(program_, tfunction->get_name() + "_result");
+  t_field success(tfunction->get_returntype(), "success", 0);
+  if (!tfunction->get_returntype()->is_void()) {
+    result.append(&success);
+  }
+
+  t_struct *xs = tfunction->get_xceptions();
+  const vector<t_field*>& fields = xs->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    result.append(*f_iter);
+  }
+
+  generate_csharp_struct_definition(f_service_, &result, false, true, true);
+}
+
+void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  indent(f_service_) <<
+    "private class " << tfunction->get_name() << " : ProcessFunction {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public void Process(int seqid, Iface iface, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << argsname << " args = new " << argsname << "();" << endl <<
+    indent() << "args.Read(iprot);" << endl <<
+    indent() << "iprot.ReadMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_async()) {
+    f_service_ <<
+      indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "try {" << endl;
+    indent_up();
+  }
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ <<
+    "iface." << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
+    f_service_ <<
+      indent() << "result.__isset.success = true;" << endl;
+  }
+
+  if (!tfunction->is_async() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " " << (*x_iter)->get_name() << ") {" << endl;
+      if (!tfunction->is_async()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << endl;
+  }
+
+  if (tfunction->is_async()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl << endl;
+    return;
+  }
+
+  f_service_ <<
+    indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.Reply, seqid)); " << endl <<
+    indent() << "result.Write(oprot);" << endl <<
+    indent() << "oprot.WriteMessageEnd();" << endl <<
+    indent() << "oprot.Transport.Flush();" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+
+  indent_down();
+
+  f_service_ <<
+    indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_deserialize_field(ofstream& out, 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()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      name << " = ";
+    
+    if (type->is_enum())
+    {
+      out << "(" << type_name(type, false, true) << ")";
+    }
+
+    out << "iprot.";
+
+    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: " + name;
+          break;
+        case t_base_type::TYPE_STRING:
+          out << "ReadString();";
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "ReadBool();";
+          break;
+        case t_base_type::TYPE_BYTE:
+          out << "ReadByte();";
+          break;
+        case t_base_type::TYPE_I16:
+          out << "ReadI16();";
+          break;
+        case t_base_type::TYPE_I32:
+          out << "ReadI32();";
+          break;
+        case t_base_type::TYPE_I64:
+          out << "ReadI64();";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out << "ReadDouble();";
+          break;
+        default:
+          throw "compiler error: no C# name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
+  out <<
+    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
+    indent() << prefix << ".Read(iprot);" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  indent(out) <<
+    prefix << " = new " << type_name(ttype, false, true) << "();" <<endl;
+  if (ttype->is_map()) {
+    out <<
+      indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl;
+  }
+
+  string i = tmp("_i");
+  indent(out) <<
+    "for( int " << i << " = 0; " << i << " < " << obj << ".Count" << "; " << "++" << i << ")" << endl;
+  scope_up(out);
+  
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "iprot.ReadMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.ReadSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.ReadListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) <<
+    declare_field(&fkey) << endl;
+  indent(out) <<
+    declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_serialize_field(ofstream& out, 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()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+    string name = prefix + tfield->get_name();
+    indent(out) <<
+      "oprot.";
+
+    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: " + name;
+          break;
+        case t_base_type::TYPE_STRING:
+          out << "WriteString(" << name << ");";
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "WriteBool(" << name << ");";
+          break;
+        case t_base_type::TYPE_BYTE:
+          out << "WriteByte(" << name << ");";
+          break;
+        case t_base_type::TYPE_I16:
+          out << "WriteI16(" << name << ");";
+          break;
+        case t_base_type::TYPE_I32:
+          out << "WriteI32(" << name << ");";
+          break;
+        case t_base_type::TYPE_I64:
+          out << "WriteI64(" << name << ");";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out << "WriteDouble(" << name << ");";
+          break;
+        default:
+          throw "compiler error: no C# name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32((int)" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
+        prefix.c_str(),
+        tfield->get_name().c_str(),
+        type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
+  out <<
+    indent() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_csharp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.WriteMapBegin(new TMap(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.WriteSetBegin(new TSet(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.WriteListBegin(new TList(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
+      " in " <<
+      prefix << ".Keys)";
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
+      " in " <<
+      prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
+      " in " <<
+      prefix << ")";
+  }
+
+  out << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListEnd();" << endl;
+  }
+
+  scope_down(out);
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter, string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "");
+}
+
+void t_csharp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+void t_csharp_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+string t_csharp_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type()) {
+    return base_type_name(((t_base_type*)ttype)->get_base(), in_container);
+  } else if (ttype->is_map()) {
+    t_map *tmap = (t_map*) ttype;
+    return "Dictionary<" + type_name(tmap->get_key_type(), true) +
+      ", " + type_name(tmap->get_val_type(), true) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*) ttype;
+    return "HashSet<" + type_name(tset->get_elem_type(), true) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*) ttype;
+    return "List<" + type_name(tlist->get_elem_type(), true) + ">";
+  }
+
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string ns = program->get_java_package();
+    if (!ns.empty()) {
+      return ns + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+string t_csharp_generator::base_type_name(t_base_type::t_base tbase, bool in_container) {
+  switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      return "void";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_BYTE:
+      return "byte";
+    case t_base_type::TYPE_I16:
+      return "short";
+    case t_base_type::TYPE_I32:
+      return "int";
+    case t_base_type::TYPE_I64:
+      return "long";
+    case t_base_type::TYPE_DOUBLE:
+      return "double";
+    default:
+      throw "compiler error: no C# name for base type " + tbase;
+  }
+}
+
+string t_csharp_generator::declare_field(t_field* tfield, bool init) {
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    t_type* ttype = tfield->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw "NO T_VOID CONSTRUCT";
+        case t_base_type::TYPE_STRING:
+          result += " = null";
+          break;
+        case t_base_type::TYPE_BOOL:
+          result += " = false";
+          break;
+        case t_base_type::TYPE_BYTE:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+          result += " = 0";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          result += " = (double)0";
+          break;
+      }
+    } else if (ttype->is_enum()) {
+      result += " = (" + type_name(ttype, false, true) + ")0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    }
+  }
+  return result + ";";
+}
+
+string t_csharp_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+  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) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_csharp_generator::type_to_enum(t_type* 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:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        return "TType.String";
+      case t_base_type::TYPE_BOOL:
+        return "TType.Bool";
+      case t_base_type::TYPE_BYTE:
+        return "TType.Byte";
+      case t_base_type::TYPE_I16:
+        return "TType.I16";
+      case t_base_type::TYPE_I32:
+        return "TType.I32";
+      case t_base_type::TYPE_I64:
+        return "TType.I64";
+      case t_base_type::TYPE_DOUBLE:
+        return "TType.Double";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.Struct";
+  } else if (type->is_map()) {
+    return "TType.Map";
+  } else if (type->is_set()) {
+    return "TType.Set";
+  } else if (type->is_list()) {
+    return "TType.List";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
diff --git a/compiler/cpp/src/generate/t_csharp_generator.h b/compiler/cpp/src/generate/t_csharp_generator.h
new file mode 100644 (file)
index 0000000..33d1491
--- /dev/null
@@ -0,0 +1,94 @@
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+#ifndef T_CSHARP_GENERATOR_H
+#define T_CSHARP_GENERATOR_H
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "t_oop_generator.h"
+
+class t_csharp_generator : public t_oop_generator
+{
+  public:
+    t_csharp_generator(t_program* program) : t_oop_generator(program) {
+      out_dir_base_ = "gen-csharp";
+    }
+    void init_generator();
+    void close_generator();
+
+    void generate_consts(std::vector<t_const*> consts);
+
+    void generate_typedef (t_typedef* ttypedef);
+    void generate_enum (t_enum* tenum);
+    void generate_struct (t_struct* tstruct);
+    void generate_xception (t_struct* txception);
+    void generate_service (t_service* tservice);
+    bool print_const_value (std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false, bool needtype=false);
+    std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+    void print_const_constructor(std::ofstream& out, std::vector<t_const*> consts);
+    void print_const_def_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
+    void generate_csharp_struct(t_struct* tstruct, bool is_exception);
+    void generate_csharp_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
+    void generate_csharp_struct_reader(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_result_writer(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_writer(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_tostring(std::ofstream& out, t_struct* tstruct);
+
+    void generate_function_helpers(t_function* tfunction);
+    void generate_service_interface (t_service* tservice);
+    void generate_service_helpers (t_service* tservice);
+    void generate_service_client (t_service* tservice);
+    void generate_service_server (t_service* tservice);
+    void generate_process_function (t_service* tservice, t_function* function);
+
+    void generate_deserialize_field (std::ofstream& out, t_field* tfield, std::string prefix="");
+    void generate_deserialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
+    void generate_deserialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
+    void generate_deserialize_set_element (std::ofstream& out, t_set* tset, std::string prefix="");
+    void generate_deserialize_map_element (std::ofstream& out, t_map* tmap, std::string prefix="");
+    void generate_deserialize_list_element (std::ofstream& out, t_list* list, std::string prefix="");
+    void generate_serialize_field (std::ofstream& out, t_field* tfield, std::string prefix="");
+    void generate_serialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
+    void generate_serialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
+    void generate_serialize_map_element (std::ofstream& out, t_map* tmap, std::string iter, std::string map);
+    void generate_serialize_set_element (std::ofstream& out, t_set* tmap, std::string iter);
+    void generate_serialize_list_element (std::ofstream& out, t_list* tlist, std::string iter);
+
+    void start_csharp_namespace (std::ofstream& out);
+    void end_csharp_namespace (std::ofstream& out);
+
+    std::string csharp_type_usings();
+    std::string csharp_thrift_usings();
+
+    std::string type_name(t_type* ttype, bool in_countainer=false, bool in_init=false);
+    std::string base_type_name(t_base_type::t_base tbase, bool in_container=false);
+    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);
+    std::string type_to_enum(t_type* ttype);
+
+    bool type_can_be_null(t_type* ttype) {
+      while (ttype->is_typedef()) {
+        ttype = ((t_typedef*)ttype)->get_type();
+      }
+
+      return ttype->is_container() ||
+        ttype->is_struct() ||
+        ttype->is_xception() ||
+        ttype->is_string();
+    }
+
+  private:
+    std::string namespace_name_;
+    std::ofstream f_service_;
+    std::string namespace_dir_;
+};
+
+#endif
index 4877431..131820a 100644 (file)
@@ -46,6 +46,7 @@
 #include "generate/t_hs_generator.h"
 #include "generate/t_cocoa_generator.h"
 #include "generate/t_st_generator.h"
+#include "generate/t_csharp_generator.h"
 
 using namespace std;
 
@@ -156,6 +157,7 @@ bool gen_erl = false;
 bool gen_ocaml = false;
 bool gen_hs = false;
 bool gen_cocoa = false;
+bool gen_csharp = false;
 bool gen_st = false;
 bool gen_recurse = false;
 
@@ -605,6 +607,7 @@ void usage() {
   fprintf(stderr, "  -ocaml      Generate OCaml output files\n");
   fprintf(stderr, "  -hs         Generate Haskell output files\n");
   fprintf(stderr, "  -cocoa      Generate Cocoa/Objective-C output files\n");
+  fprintf(stderr, "  -csharp     Generate C# output files\n");
   fprintf(stderr, "  -st         Generate Squeak/Smalltalk output files\n");
   fprintf(stderr, "  -o dir      Set the output directory for gen-* packages\n");
   fprintf(stderr, "               (default: current directory)\n");
@@ -924,6 +927,13 @@ void generate(t_program* program) {
       delete st;
     }
 
+    if (gen_csharp) {
+      pverbose("Generating C#\n");
+      t_csharp_generator* csharp = new t_csharp_generator(program);
+      csharp->generate_program();
+      delete csharp;
+    }
+       
     if (dump_docs) {
       dump_docstrings(program);
     }
@@ -1022,6 +1032,8 @@ int main(int argc, char** argv) {
         gen_cocoa = true;
       } else if (strcmp(arg, "-st") == 0) {
         gen_st = true;
+      } else if (strcmp(arg, "-csharp") == 0) {
+        gen_csharp = true;
       } else if (strcmp(arg, "-I") == 0) {
         // An argument of "-I\ asdf" is invalid and has unknown results
         arg = argv[++i];
@@ -1068,7 +1080,7 @@ int main(int argc, char** argv) {
   }
 
   // You gotta generate something!
-  if (!gen_cpp && !gen_java && !gen_javabean && !gen_php && !gen_phpi && !gen_py && !gen_rb && !gen_xsd && !gen_perl && !gen_erl && !gen_ocaml && !gen_hs && !gen_cocoa && !gen_st) {
+  if (!gen_cpp && !gen_java && !gen_javabean && !gen_php && !gen_phpi && !gen_py && !gen_rb && !gen_xsd && !gen_perl && !gen_erl && !gen_ocaml && !gen_hs && !gen_cocoa && !gen_st && !gen_csharp) {
     fprintf(stderr, "!!! No output language(s) specified\n\n");
     usage();
   }
index dc8c80c..66f0620 100644 (file)
@@ -152,6 +152,14 @@ class t_program : public t_doc {
     return java_package_;
   }
 
+  void set_csharp_namespace(std::string csharp_namespace) {
+    csharp_namespace_ = csharp_namespace;
+  }
+
+  const std::string& get_csharp_namespace() const {
+    return csharp_namespace_;
+  }
+
   void set_xsd_namespace(std::string xsd_namespace) {
     xsd_namespace_ = xsd_namespace;
   }
@@ -267,6 +275,9 @@ class t_program : public t_doc {
   std::string smalltalk_category_;
   // Smalltalk prefix
   std::string smalltalk_prefix_;
+
+  // C# namespace
+  std::string csharp_namespace_;
 };
 
 #endif
index 0889a12..21a0dd7 100644 (file)
@@ -73,6 +73,7 @@ st_identifier ([a-zA-Z-][\.a-zA-Z_0-9-]*)
 "cpp_type"           { return tok_cpp_type;             }
 "java_package"       { return tok_java_package;         }
 "cocoa_prefix"       { return tok_cocoa_prefix;         }
+"csharp_namespace"   { return tok_csharp_namespace;     }
 "php_namespace"      { return tok_php_namespace;        }
 "py_module"          { return tok_py_module;            }
 "perl_package"       { return tok_perl_package;         }
index 9475adf..5be19b3 100644 (file)
@@ -89,6 +89,7 @@ int g_arglist = 0;
 %token tok_smalltalk_category
 %token tok_smalltalk_prefix
 %token tok_cocoa_prefix
+%token tok_csharp_namespace
 
 /**
  * Base datatype keywords
@@ -331,6 +332,13 @@ Header:
         g_program->set_xsd_namespace($2);
       }
     }
+| tok_csharp_namespace tok_identifier
+   {
+     pdebug("Header -> tok_csharp_package tok_identifier");
+     if (g_parse_mode == PROGRAM) {
+       g_program->set_csharp_namespace($2);
+     }
+   }
 
 Include:
   tok_include tok_literal
diff --git a/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..4375a52
--- /dev/null
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ThriftMSBuildTask")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ThriftMSBuildTask")]
+[assembly: AssemblyCopyright("Copyright Â©  2007")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5095e09d-7b95-4be1-b250-e1c1db1c485e")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
new file mode 100644 (file)
index 0000000..9cf5f41
--- /dev/null
@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.Tasks;
+using System.IO;
+using System.Diagnostics;
+
+namespace ThriftMSBuildTask
+{
+       /// <summary>
+       /// MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll
+       /// </summary>
+       public class ThriftBuild : Task
+       {
+               /// <summary>
+               /// The full path to the thrift.exe compiler
+               /// </summary>
+               [Required]
+               public ITaskItem ThriftExecutable
+               {
+                       get;
+                       set;
+               }
+
+               /// <summary>
+               /// The full path to a thrift.dll C# library
+               /// </summary>
+               [Required]
+               public ITaskItem ThriftLibrary
+               {
+                       get;
+                       set;
+               }
+
+               /// <summary>
+               /// A direcotry containing .thrift files
+               /// </summary>
+               [Required]
+               public ITaskItem ThriftDefinitionDir
+               {
+                       get;
+                       set;
+               }
+
+               /// <summary>
+               /// The name of the auto-gen and compiled thrift library. It will placed in
+               /// the same directory as ThriftLibrary
+               /// </summary>
+               [Required]
+               public ITaskItem OutputName
+               {
+                       get;
+                       set;
+               }
+
+               /// <summary>
+               /// The full path to the compiled ThriftLibrary. This allows msbuild tasks to use this
+               /// output as a variable for use elsewhere.
+               /// </summary>
+               [Output]
+               public ITaskItem ThriftImplementation
+               {
+                       get { return thriftImpl; }
+               }
+
+               private ITaskItem thriftImpl;
+               private const string lastCompilationName = "LAST_COMP_TIMESTAMP";
+
+               //use the Message Build Task to write something to build log
+               private void LogMessage(string text, MessageImportance importance)
+               {
+                       Message m = new Message();
+                       m.Text = text;
+                       m.Importance = importance.ToString();
+                       m.BuildEngine = this.BuildEngine;
+                       m.Execute();
+               }
+
+               //recursively find .cs files in srcDir, paths should initially be non-null and empty
+               private void FindSourcesHelper(string srcDir, List<string> paths)
+               {
+                       string[] files = Directory.GetFiles(srcDir, "*.cs");
+                       foreach (string f in files)
+                       {
+                               paths.Add(f);
+                       }
+                       string[] dirs = Directory.GetDirectories(srcDir);
+                       foreach (string dir in dirs)
+                       {
+                               FindSourcesHelper(dir, paths);
+                       }
+               }
+
+               /// <summary>
+               /// Quote paths with spaces
+               /// </summary>
+               private string SafePath(string path)
+               {
+                       if (path.Contains(' ') && !path.StartsWith("\""))
+                       {
+                               return "\"" + path + "\"";
+                       }
+                       return path;
+               }
+
+               private ITaskItem[] FindSources(string srcDir)
+               {
+                       List<string> files = new List<string>();
+                       FindSourcesHelper(srcDir, files);
+                       ITaskItem[] items = new ITaskItem[files.Count];
+                       for (int i = 0; i < items.Length; i++)
+                       {
+                               items[i] = new TaskItem(files[i]);
+                       }
+                       return items;
+               }
+
+               private string LastWriteTime(string defDir)
+               {
+                       string[] files = Directory.GetFiles(defDir, "*.thrift");
+                       DateTime d = (new DirectoryInfo(defDir)).LastWriteTime;
+                       foreach(string file in files)
+                       {
+                               FileInfo f = new FileInfo(file);
+                               DateTime curr = f.LastWriteTime;
+                               if (DateTime.Compare(curr, d) > 0)
+                               {
+                                       d = curr;
+                               }
+                       }
+                       return d.ToFileTimeUtc().ToString();
+               }
+
+               public override bool Execute()
+               {
+                       string defDir = SafePath(ThriftDefinitionDir.ItemSpec);
+                       //look for last compilation timestamp
+                       string lastBuildPath = Path.Combine(defDir, lastCompilationName);
+                       DirectoryInfo defDirInfo = new DirectoryInfo(defDir);
+                       string lastWrite = LastWriteTime(defDir);
+                       if (File.Exists(lastBuildPath))
+                       {
+                               string lastComp = File.ReadAllText(lastBuildPath);
+
+                               if (lastComp == lastWrite)
+                               {
+                                       //the .thrift dir hasn't been written to since last compilation, don't need to do anything
+                                       LogMessage("ThriftImpl up-to-date", MessageImportance.Normal);
+                                       return true;
+                               }
+                       }
+
+                       //find the directory of the thriftlibrary (that's where output will go)
+                       FileInfo thriftLibInfo = new FileInfo(SafePath(ThriftLibrary.ItemSpec));
+                       string thriftDir = thriftLibInfo.Directory.FullName;
+
+                       string genDir = Path.Combine(thriftDir, "gen-csharp");
+                       if (Directory.Exists(genDir))
+                       {
+                               Directory.Delete(genDir, true);
+                       }
+                       
+                       //run the thrift executable to generate C#
+                       foreach (string thriftFile in Directory.GetFiles(defDir, "*.thrift"))
+                       {
+                               LogMessage("Generating code for: " + thriftFile, MessageImportance.Normal);
+                               Process p = new Process();
+                               p.StartInfo.FileName = SafePath(ThriftExecutable.ItemSpec);
+                               p.StartInfo.Arguments = "-csharp -o " + SafePath(thriftDir) + " -r " + thriftFile;
+                               p.StartInfo.UseShellExecute = false;
+                               p.StartInfo.CreateNoWindow = true;
+                               p.StartInfo.RedirectStandardOutput = false;
+                               p.Start();
+                               p.WaitForExit();
+                       }
+
+                       Csc csc = new Csc();
+                       csc.TargetType = "library";
+                       csc.References = new ITaskItem[] { new TaskItem(ThriftLibrary.ItemSpec) };
+                       csc.EmitDebugInformation = true;
+                       string outputPath = Path.Combine(thriftDir, OutputName.ItemSpec);
+                       csc.OutputAssembly = new TaskItem(outputPath);
+                       csc.Sources = FindSources(Path.Combine(thriftDir, "gen-csharp"));
+                       csc.BuildEngine = this.BuildEngine;
+                       LogMessage("Compiling generated cs...", MessageImportance.Normal);
+                       if (!csc.Execute())
+                       {
+                               return false;
+                       }
+
+                       //write file to defDir to indicate a build was successfully completed
+                       File.WriteAllText(lastBuildPath, lastWrite);
+
+                       thriftImpl = new TaskItem(outputPath);
+
+                       return true;
+               }
+       }
+}
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
new file mode 100644 (file)
index 0000000..68c6bd1
--- /dev/null
@@ -0,0 +1,66 @@
+\feff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{EC0A0231-66EA-4593-A792-C6CA3BB8668E}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftMSBuildTask</RootNamespace>
+    <AssemblyName>ThriftMSBuildTask</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Build.Framework" />
+    <Reference Include="Microsoft.Build.Tasks" />
+    <Reference Include="Microsoft.Build.Utilities" />
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ThriftBuild.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Protocol/TBinaryProtocol.cs b/lib/csharp/src/Protocol/TBinaryProtocol.cs
new file mode 100644 (file)
index 0000000..36f03d0
--- /dev/null
@@ -0,0 +1,386 @@
+//
+//  TBinaryProtocol.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//             Will Palmeri <will@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+       public class TBinaryProtocol : TProtocol
+       {
+               protected const uint VERSION_MASK = 0xffff0000;
+               protected const uint VERSION_1 = 0x80010000;
+
+               protected bool strictRead_ = false;
+               protected bool strictWrite_ = true;
+
+               protected int readLength_;
+               protected bool checkReadLength_ = false;
+
+
+               #region BinaryProtocol Factory
+                /**
+                 * Factory
+                 */
+                 public class Factory : TProtocolFactory {
+
+                         protected bool strictRead_ = false;
+                         protected bool strictWrite_ = true;
+
+                         public Factory()
+                                 :this(false, true)
+                         {
+                         }
+
+                         public Factory(bool strictRead, bool strictWrite)
+                         {
+                                 strictRead_ = strictRead;
+                                 strictWrite_ = strictWrite;
+                         }
+
+                       public TProtocol GetProtocol(TTransport trans) {
+                         return new TBinaryProtocol(trans, strictRead_, strictWrite_);
+                       }
+                 }
+
+               #endregion
+
+               public TBinaryProtocol(TTransport trans)
+                       : this(trans, false, true)
+               {
+               }
+
+               public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite)
+                       :base(trans)
+               {
+                       strictRead_ = strictRead;
+                       strictWrite_ = strictWrite;
+               }
+
+               #region Write Methods
+
+               public override void WriteMessageBegin(TMessage message)
+               {
+                       if (strictWrite_)
+                       {
+                               uint version = VERSION_1 | (uint)(message.Type);
+                               WriteI32((int)version);
+                               WriteString(message.Name);
+                               WriteI32(message.SeqID);
+                       }
+                       else
+                       {
+                               WriteString(message.Name);
+                               WriteByte((byte)message.Type);
+                               WriteI32(message.SeqID);
+                       }
+               }
+
+               public override void WriteMessageEnd()
+               {
+               }
+
+               public override void WriteStructBegin(TStruct struc)
+               {
+               }
+
+               public override void WriteStructEnd()
+               {
+               }
+
+               public override void WriteFieldBegin(TField field)
+               {
+                       WriteByte((byte)field.Type);
+                       WriteI16(field.ID);
+               }
+
+               public override void WriteFieldEnd()
+               {
+               }
+
+               public override void WriteFieldStop()
+               {
+                       WriteByte((byte)TType.Stop);
+               }
+
+               public override void WriteMapBegin(TMap map)
+               {
+                       WriteByte((byte)map.KeyType);
+                       WriteByte((byte)map.ValueType);
+                       WriteI32(map.Count);
+               }
+
+               public override void WriteMapEnd()
+               {
+               }
+
+               public override void WriteListBegin(TList list)
+               {
+                       WriteByte((byte)list.ElementType);
+                       WriteI32(list.Count);
+               }
+
+               public override void WriteListEnd()
+               {
+               }
+
+               public override void WriteSetBegin(TSet set)
+               {
+                       WriteByte((byte)set.ElementType);
+                       WriteI32(set.Count);
+               }
+
+               public override void WriteSetEnd()
+               {
+               }
+
+               public override void WriteBool(bool b)
+               {
+                       WriteByte(b ? (byte)1 : (byte)0);
+               }
+
+               private byte[] bout = new byte[1];
+               public override void WriteByte(byte b)
+               {
+                       bout[0] = b;
+                       trans.Write(bout, 0, 1);
+               }
+
+               private byte[] i16out = new byte[2];
+               public override void WriteI16(short s)
+               {
+                       i16out[0] = (byte)(0xff & (s >> 8));
+                       i16out[1] = (byte)(0xff & s);
+                       trans.Write(i16out, 0, 2);
+               }
+
+               private byte[] i32out = new byte[4];
+               public override void WriteI32(int i32)
+               {
+                       i32out[0] = (byte)(0xff & (i32 >> 24));
+                       i32out[1] = (byte)(0xff & (i32 >> 16));
+                       i32out[2] = (byte)(0xff & (i32 >> 8));
+                       i32out[3] = (byte)(0xff & i32);
+                       trans.Write(i32out, 0, 4);
+               }
+
+               private byte[] i64out = new byte[8];
+               public override void WriteI64(long i64)
+               {
+                       i64out[0] = (byte)(0xff & (i64 >> 56));
+                       i64out[1] = (byte)(0xff & (i64 >> 48));
+                       i64out[2] = (byte)(0xff & (i64 >> 40));
+                       i64out[3] = (byte)(0xff & (i64 >> 32));
+                       i64out[4] = (byte)(0xff & (i64 >> 24));
+                       i64out[5] = (byte)(0xff & (i64 >> 16));
+                       i64out[6] = (byte)(0xff & (i64 >> 8));
+                       i64out[7] = (byte)(0xff & i64);
+                       trans.Write(i64out, 0, 8);
+               }
+
+               public override void WriteDouble(double d)
+               {
+                       WriteI64(BitConverter.DoubleToInt64Bits(d));
+               }
+
+               public override void WriteString(string s)
+               {
+                       byte[] b = Encoding.UTF8.GetBytes(s);
+                       WriteI32(b.Length);
+                       trans.Write(b, 0, b.Length);
+               }
+
+               #endregion
+
+               #region ReadMethods
+
+               public override TMessage ReadMessageBegin()
+               {
+                       TMessage message = new TMessage();
+                       int size = ReadI32();
+                       if (size < 0)
+                       {
+                               uint version = (uint)size & VERSION_MASK;
+                               if (version != VERSION_1)
+                               {
+                                       throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in ReadMessageBegin: " + version);
+                               }
+                               message.Type = (TMessageType)(size & 0x000000ff);
+                               message.Name = ReadString();
+                               message.SeqID = ReadI32();
+                       }
+                       else
+                       {
+                               if (strictRead_)
+                               {
+                                       throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+                               }
+                               message.Name = ReadStringBody(size);
+                               message.Type = (TMessageType)ReadByte();
+                               message.SeqID = ReadI32();
+                       }
+                       return message;
+               }
+
+               public override void ReadMessageEnd()
+               {
+               }
+
+               public override TStruct ReadStructBegin()
+               {
+                       return new TStruct();
+               }
+
+               public override void ReadStructEnd()
+               {
+               }
+
+               public override TField ReadFieldBegin()
+               {
+                       TField field = new TField();
+                       field.Type = (TType)ReadByte();
+
+                       if (field.Type != TType.Stop)
+                       {
+                               field.ID = ReadI16();
+                       }
+
+                       return field;
+               }
+
+               public override void ReadFieldEnd()
+               {
+               }
+
+               public override TMap ReadMapBegin()
+               {
+                       TMap map = new TMap();
+                       map.KeyType = (TType)ReadByte();
+                       map.ValueType = (TType)ReadByte();
+                       map.Count = ReadI32();
+
+                       return map;
+               }
+
+               public override void ReadMapEnd()
+               {
+               }
+
+               public override TList ReadListBegin()
+               {
+                       TList list = new TList();
+                       list.ElementType = (TType)ReadByte();
+                       list.Count = ReadI32();
+
+                       return list;
+               }
+
+               public override void ReadListEnd()
+               {
+               }
+
+               public override TSet ReadSetBegin()
+               {
+                       TSet set = new TSet();
+                       set.ElementType = (TType)ReadByte();
+                       set.Count = ReadI32();
+
+                       return set;
+               }
+
+               public override void ReadSetEnd()
+               {
+               }
+
+               public override bool ReadBool()
+               {
+                       return ReadByte() == 1;
+               }
+
+               private byte[] bin = new byte[1];
+               public override byte ReadByte()
+               {
+                       ReadAll(bin, 0, 1);
+                       return bin[0];
+               }
+
+               private byte[] i16in = new byte[2];
+               public override short ReadI16()
+               {
+                       ReadAll(i16in, 0, 2);
+                       return (short)(((i16in[0] & 0xff) << 8) | ((i16in[1] & 0xff)));
+               }
+
+               private byte[] i32in = new byte[4];
+               public override int ReadI32()
+               {
+                       ReadAll(i32in, 0, 4);
+                       return (int)(((i32in[0] & 0xff) << 24) | ((i32in[1] & 0xff) << 16) | ((i32in[2] & 0xff) << 8) | ((i32in[3] & 0xff)));
+               }
+
+               private byte[] i64in = new byte[8];
+               public override long ReadI64()
+               {
+                       ReadAll(i64in, 0, 8);
+                       return (long)(((long)(i64in[0] & 0xff) << 56) | ((long)(i64in[1] & 0xff) << 48) | ((long)(i64in[2] & 0xff) << 40) | ((long)(i64in[3] & 0xff) << 32) |
+                               ((long)(i64in[4] & 0xff) << 24) | ((long)(i64in[5] & 0xff) << 16) | ((long)(i64in[6] & 0xff) << 8) | ((long)(i64in[7] & 0xff)));
+               }
+
+               public override double ReadDouble()
+               {
+                       return BitConverter.Int64BitsToDouble(ReadI64());
+               }
+
+               public void SetReadLength(int readLength)
+               {
+                       readLength_ = readLength;
+                       checkReadLength_ = true;
+               }
+
+               protected void CheckReadLength(int length)
+               {
+                       if (checkReadLength_)
+                       {
+                               readLength_ -= length;
+                               if (readLength_ < 0)
+                               {
+                                       throw new Exception("Message length exceeded: " + length);
+                               }
+                       }
+               }
+
+               public override string ReadString()
+               {
+                       int size = ReadI32();
+                       return ReadStringBody(size);
+               }
+
+               public string ReadStringBody(int size)
+               {
+                       CheckReadLength(size);
+                       byte[] buf = new byte[size];
+                       trans.ReadAll(buf, 0, size);
+                       return Encoding.UTF8.GetString(buf);
+               }
+
+               private int ReadAll(byte[] buf, int off, int len)
+               {
+                       CheckReadLength(len);
+                       return trans.ReadAll(buf, off, len);
+               }
+
+               #endregion
+       }
+}
diff --git a/lib/csharp/src/Protocol/TField.cs b/lib/csharp/src/Protocol/TField.cs
new file mode 100644 (file)
index 0000000..f18381f
--- /dev/null
@@ -0,0 +1,50 @@
+//
+//  TField.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TField
+       {
+               public TField()
+               {
+               }
+
+               public TField(string name, TType type, short id)
+               {
+                       Name = name;
+                       Type = type;
+                       ID = id;
+               }
+
+               public string Name
+               {
+                       get;
+                       set;
+               }
+
+               public TType Type
+               {
+                       get;
+                       set;
+               }
+
+               public short ID
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TList.cs b/lib/csharp/src/Protocol/TList.cs
new file mode 100644 (file)
index 0000000..ff6aa53
--- /dev/null
@@ -0,0 +1,43 @@
+//
+//  TList.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TList
+       {
+               public TList()
+               {
+               }
+
+               public TList(TType elementType, int count)
+               {
+                       ElementType = elementType;
+                       Count = count;
+               }
+
+               public TType ElementType
+               {
+                       get;
+                       set;
+               }
+
+               public int Count
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TMap.cs b/lib/csharp/src/Protocol/TMap.cs
new file mode 100644 (file)
index 0000000..495bf7c
--- /dev/null
@@ -0,0 +1,50 @@
+//
+//  TMap.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TMap
+       {
+               public TMap()
+               {
+               }
+
+               public TMap(TType keyType, TType valueType, int count)
+               {
+                       KeyType = keyType;
+                       ValueType = valueType;
+                       Count = count;
+               }
+
+               public TType KeyType
+               {
+                       get;
+                       set;
+               }
+
+               public TType ValueType
+               {
+                       get;
+                       set;
+               }
+
+               public int Count
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TMessage.cs b/lib/csharp/src/Protocol/TMessage.cs
new file mode 100644 (file)
index 0000000..60df660
--- /dev/null
@@ -0,0 +1,50 @@
+//
+//  TMessage.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TMessage
+       {
+               public TMessage()
+               {
+               }
+
+               public TMessage(string name, TMessageType type, int seqid)
+               {
+                       Name = name;
+                       Type = type;
+                       SeqID = seqid;
+               }
+
+               public string Name
+               {
+                       get;
+                       set;
+               }
+
+               public TMessageType Type
+               {
+                       get;
+                       set;
+               }
+
+               public int SeqID
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TMessageType.cs b/lib/csharp/src/Protocol/TMessageType.cs
new file mode 100644 (file)
index 0000000..1cadf31
--- /dev/null
@@ -0,0 +1,25 @@
+//
+//  TMessageType.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public enum TMessageType
+       {
+               Call = 1,
+               Reply = 2,
+               Exception = 3
+       }
+}
diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs
new file mode 100644 (file)
index 0000000..f46b6d1
--- /dev/null
@@ -0,0 +1,75 @@
+//
+//  TProtocol.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+       public abstract class TProtocol
+       {
+               protected TTransport trans;
+
+               protected TProtocol(TTransport trans)
+               {
+                       this.trans = trans;
+               }
+
+               public TTransport Transport
+               {
+                       get { return trans; }
+               }
+
+               public abstract void WriteMessageBegin(TMessage message);
+               public abstract void WriteMessageEnd();
+               public abstract void WriteStructBegin(TStruct struc);
+               public abstract void WriteStructEnd();
+               public abstract void WriteFieldBegin(TField field);
+               public abstract void WriteFieldEnd();
+               public abstract void WriteFieldStop();
+               public abstract void WriteMapBegin(TMap map);
+               public abstract void WriteMapEnd();
+               public abstract void WriteListBegin(TList list);
+               public abstract void WriteListEnd();
+               public abstract void WriteSetBegin(TSet set);
+               public abstract void WriteSetEnd();
+               public abstract void WriteBool(bool b);
+               public abstract void WriteByte(byte b);
+               public abstract void WriteI16(short i16);
+               public abstract void WriteI32(int i32);
+               public abstract void WriteI64(long i64);
+               public abstract void WriteDouble(double d);
+               public abstract void WriteString(string s);
+
+               public abstract TMessage ReadMessageBegin();
+               public abstract void ReadMessageEnd();
+               public abstract TStruct ReadStructBegin();
+               public abstract void ReadStructEnd();
+               public abstract TField ReadFieldBegin();
+               public abstract void ReadFieldEnd();
+               public abstract TMap ReadMapBegin();
+               public abstract void ReadMapEnd();
+               public abstract TList ReadListBegin();
+               public abstract void ReadListEnd();
+               public abstract TSet ReadSetBegin();
+               public abstract void ReadSetEnd();
+               public abstract bool ReadBool();
+               public abstract byte ReadByte();
+               public abstract short ReadI16();
+               public abstract int ReadI32();
+               public abstract long ReadI64();
+               public abstract double ReadDouble();
+               public abstract string ReadString();
+       }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolException.cs b/lib/csharp/src/Protocol/TProtocolException.cs
new file mode 100644 (file)
index 0000000..0941a81
--- /dev/null
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       class TProtocolException : Exception
+       {
+               public const int UNKNOWN = 0;
+               public const int INVALID_DATA = 1;
+               public const int NEGATIVE_SIZE = 2;
+               public const int SIZE_LIMIT = 3;
+               public const int BAD_VERSION = 4;
+
+               protected int type_ = UNKNOWN;
+
+               public TProtocolException()
+                       : base()
+               {
+               }
+
+               public TProtocolException(int type)
+                       : base()
+               {
+                       type_ = type;
+               }
+
+               public TProtocolException(int type, String message)
+                       : base(message)
+               {
+                       type_ = type;
+               }
+
+               public TProtocolException(String message)
+                       : base(message)
+               {
+               }
+
+               public int getType()
+               {
+                       return type_;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolFactory.cs b/lib/csharp/src/Protocol/TProtocolFactory.cs
new file mode 100644 (file)
index 0000000..5434da9
--- /dev/null
@@ -0,0 +1,23 @@
+//
+//  TProtocolFactory.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+       public interface TProtocolFactory
+       {
+               TProtocol GetProtocol(TTransport trans);
+       }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolUtil.cs b/lib/csharp/src/Protocol/TProtocolUtil.cs
new file mode 100644 (file)
index 0000000..67f0ce6
--- /dev/null
@@ -0,0 +1,88 @@
+//
+//  TProtocolUtil.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public static class TProtocolUtil
+       {
+               public static void Skip(TProtocol prot, TType type)
+               {
+                       switch (type)
+                       {
+                               case TType.Bool:
+                                       prot.ReadBool();
+                                       break;
+                               case TType.Byte:
+                                       prot.ReadByte();
+                                       break;
+                               case TType.I16:
+                                       prot.ReadI16();
+                                       break;
+                               case TType.I32:
+                                       prot.ReadI32();
+                                       break;
+                               case TType.I64:
+                                       prot.ReadI64();
+                                       break;
+                               case TType.Double:
+                                       prot.ReadDouble();
+                                       break;
+                               case TType.String:
+                                       prot.ReadString();
+                                       break;
+                               case TType.Struct:
+                                       prot.ReadStructBegin();
+                                       while (true)
+                                       {
+                                               TField field = prot.ReadFieldBegin();
+                                               if (field.Type == TType.Stop)
+                                               {
+                                                       break;
+                                               }
+                                               Skip(prot, field.Type);
+                                               prot.ReadFieldEnd();
+                                       }
+                                       prot.ReadStructEnd();
+                                       break;
+                               case TType.Map:
+                                       TMap map = prot.ReadMapBegin();
+                                       for (int i = 0; i < map.Count; i++)
+                                       {
+                                               Skip(prot, map.KeyType);
+                                               Skip(prot, map.ValueType);
+                                       }
+                                       prot.ReadMapEnd();
+                                       break;
+                               case TType.Set:
+                                       TSet set = prot.ReadSetBegin();
+                                       for (int i = 0; i < set.Count; i++)
+                                       {
+                                               Skip(prot, set.ElementType);
+                                       }
+                                       prot.ReadSetEnd();
+                                       break;
+                               case TType.List:
+                                       TList list = prot.ReadListBegin();
+                                       for (int i = 0; i < list.Count; i++)
+                                       {
+                                               Skip(prot, list.ElementType);
+                                       }
+                                       prot.ReadListEnd();
+                                       break;
+                       }
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TSet.cs b/lib/csharp/src/Protocol/TSet.cs
new file mode 100644 (file)
index 0000000..c4c6fc3
--- /dev/null
@@ -0,0 +1,43 @@
+//
+//  TSet.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TSet
+       {
+               public TSet()
+               {
+               }
+
+               public TSet(TType elementType, int count)
+               {
+                       ElementType = elementType;
+                       Count = count;
+               }
+
+               public TType ElementType
+               {
+                       get;
+                       set;
+               }
+
+               public int Count
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TStruct.cs b/lib/csharp/src/Protocol/TStruct.cs
new file mode 100644 (file)
index 0000000..88f12df
--- /dev/null
@@ -0,0 +1,35 @@
+//
+//  TStruct.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public class TStruct
+       {
+               public TStruct()
+               {
+               }
+
+               public TStruct(string name)
+               {
+                       Name = name;
+               }
+
+               public string Name
+               {
+                       get;
+                       set;
+               }
+       }
+}
diff --git a/lib/csharp/src/Protocol/TType.cs b/lib/csharp/src/Protocol/TType.cs
new file mode 100644 (file)
index 0000000..0badb33
--- /dev/null
@@ -0,0 +1,35 @@
+//
+//  TType.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+       public enum TType : byte
+       {
+               Stop = 0,
+               Void = 1,
+               Bool = 2,
+               Byte = 3,
+               Double = 4,
+               I16 = 6,
+               I32 = 8,
+               I64 = 10,
+               String = 11,
+               Struct = 12,
+               Map = 13,
+               Set = 14,
+               List = 15
+       }
+}
diff --git a/lib/csharp/src/Server/TServer.cs b/lib/csharp/src/Server/TServer.cs
new file mode 100644 (file)
index 0000000..3e70b11
--- /dev/null
@@ -0,0 +1,108 @@
+//
+//  TServer.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace Thrift.Server
+{
+       public abstract class TServer
+       {
+               /**
+                * Core processor
+                */
+               protected TProcessor processor;
+
+               /**
+                * Server transport
+                */
+               protected TServerTransport serverTransport;
+
+               /**
+                * Input Transport Factory
+                */
+               protected TTransportFactory inputTransportFactory;
+
+               /**
+                * Output Transport Factory
+                */
+               protected TTransportFactory outputTransportFactory;
+
+               /**
+                * Input Protocol Factory
+                */
+               protected TProtocolFactory inputProtocolFactory;
+
+               /**
+                * Output Protocol Factory
+                */
+               protected TProtocolFactory outputProtocolFactory;
+
+               /**
+                * Default constructors.
+                */
+
+               public TServer(TProcessor processor,
+                                                 TServerTransport serverTransport)
+                       :this(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory())
+               {
+               }
+
+               public TServer(TProcessor processor,
+                                                 TServerTransport serverTransport,
+                                                 TTransportFactory transportFactory)
+                       :this(processor,
+                                serverTransport,
+                                transportFactory,
+                                transportFactory,
+                                new TBinaryProtocol.Factory(),
+                                new TBinaryProtocol.Factory())
+               {
+               }
+
+               public TServer(TProcessor processor,
+                                                 TServerTransport serverTransport,
+                                                 TTransportFactory transportFactory,
+                                                 TProtocolFactory protocolFactory)
+                       :this(processor,
+                                serverTransport,
+                                transportFactory,
+                                transportFactory,
+                                protocolFactory,
+                                protocolFactory)
+               {
+               }
+
+               public TServer(TProcessor processor,
+                                                 TServerTransport serverTransport,
+                                                 TTransportFactory inputTransportFactory,
+                                                 TTransportFactory outputTransportFactory,
+                                                 TProtocolFactory inputProtocolFactory,
+                                                 TProtocolFactory outputProtocolFactory)
+               {
+                       this.processor = processor;
+                       this.serverTransport = serverTransport;
+                       this.inputTransportFactory = inputTransportFactory;
+                       this.outputTransportFactory = outputTransportFactory;
+                       this.inputProtocolFactory = inputProtocolFactory;
+                       this.outputProtocolFactory = outputProtocolFactory;
+               }
+
+               /**
+                * The run method fires up the server and gets things going.
+                */
+               public abstract void Serve();
+       }
+}
+
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
new file mode 100644 (file)
index 0000000..c3461ef
--- /dev/null
@@ -0,0 +1,108 @@
+//
+//  TSimpleServer.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Transport;
+using Thrift.Protocol;
+
+namespace Thrift.Server
+{
+       /// <summary>
+       /// Simple single-threaded server for testing
+       /// </summary>
+       class TSimpleServer : TServer
+       {
+               public TSimpleServer(TProcessor processor,
+                                                 TServerTransport serverTransport)
+                       :base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory())
+               {
+               }
+
+               public TSimpleServer(TProcessor processor,
+                                                 TServerTransport serverTransport,
+                                                 TTransportFactory transportFactory)
+                       :base(processor,
+                                serverTransport,
+                                transportFactory,
+                                transportFactory,
+                                new TBinaryProtocol.Factory(),
+                                new TBinaryProtocol.Factory())
+               {
+               }
+
+               public TSimpleServer(TProcessor processor,
+                                                 TServerTransport serverTransport,
+                                                 TTransportFactory transportFactory,
+                                                 TProtocolFactory protocolFactory)
+                       :base(processor,
+                                serverTransport,
+                                transportFactory,
+                                transportFactory,
+                                protocolFactory,
+                                protocolFactory)
+               {
+               }
+
+               public override void Serve()
+               {
+                       try
+                       {
+                               serverTransport.Listen();
+                       }
+                       catch (TTransportException ttx)
+                       {
+                               Console.Error.WriteLine(ttx);
+                               return;
+                       }
+
+                       while (true)
+                       {
+                               TTransport client = null;
+                               TTransport inputTransport = null;
+                               TTransport outputTransport = null;
+                               TProtocol inputProtocol = null;
+                               TProtocol outputProtocol = null;
+                               try
+                               {
+                                       client = serverTransport.Accept();
+                                       if (client != null)
+                                       {
+                                               inputTransport = inputTransportFactory.GetTransport(client);
+                                               outputTransport = outputTransportFactory.GetTransport(client);
+                                               inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                                               outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+                                               while (processor.Process(inputProtocol, outputProtocol)) { }
+                                       }
+                               }
+                               catch (TTransportException ttx)
+                               {
+                                       // Client died, just move on
+                               }
+                               catch (Exception x)
+                               {
+                                       Console.Error.WriteLine(x);
+                               }
+
+                               if (inputTransport != null)
+                               {
+                                       inputTransport.Close();
+                               }
+
+                               if (outputTransport != null)
+                               {
+                                       outputTransport.Close();
+                               }
+                       }
+               }
+       }
+}
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
new file mode 100644 (file)
index 0000000..c42d348
--- /dev/null
@@ -0,0 +1,143 @@
+//
+//  TThreadPoolServer.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace Thrift.Server
+{
+       /// <summary>
+       /// Server that uses C# built-in ThreadPool to spawn threads when handling requests
+       /// </summary>
+       public class TThreadPoolServer : TServer
+       {
+               private const int DEFAULT_MIN_THREADS = 10;
+               private const int DEFAULT_MAX_THREADS = 100;
+
+               public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
+                       :this(processor, serverTransport,
+                                new TTransportFactory(), new TTransportFactory(),
+                                new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+                                DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS)
+               {
+               }
+
+               public TThreadPoolServer(TProcessor processor,
+                                                                TServerTransport serverTransport,
+                                                                TTransportFactory transportFactory,
+                                                                TProtocolFactory protocolFactory)
+                       :this(processor, serverTransport,
+                                transportFactory, transportFactory,
+                                protocolFactory, protocolFactory,
+                                DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS)
+               {
+               }
+
+               public TThreadPoolServer(TProcessor processor,
+                                                                TServerTransport serverTransport,
+                                                                TTransportFactory inputTransportFactory,
+                                                                TTransportFactory outputTransportFactory,
+                                                                TProtocolFactory inputProtocolFactory,
+                                                                TProtocolFactory outputProtocolFactory,
+                                                                int minThreadPoolThreads, int maxThreadPoolThreads)
+                       :base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
+                                 inputProtocolFactory, outputProtocolFactory)
+               {
+                       if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
+                       {
+                               throw new Exception("Error: could not SetMinThreads in ThreadPool");
+                       }
+                       if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
+                       {
+                               throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+                       }
+
+               }
+
+               /// <summary>
+               /// Use new ThreadPool thread for each new client connection
+               /// </summary>
+               public override void Serve()
+               {
+                       try
+                       {
+                               serverTransport.Listen();
+                       }
+                       catch (TTransportException ttx)
+                       {
+                               Console.Error.WriteLine("Error, could not listen on ServerTransport: " + ttx);
+                               return;
+                       }
+
+                       while (true)
+                       {
+                               int failureCount = 0;
+                               try
+                               {
+                                       TTransport client = serverTransport.Accept();
+                                       ThreadPool.QueueUserWorkItem(this.Execute, client);
+                               }
+                               catch (TTransportException ttx)
+                               {
+                                       ++failureCount;
+                                       Console.Error.WriteLine(ttx);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Loops on processing a client forever
+               /// threadContext will be a TTransport instance
+               /// </summary>
+               /// <param name="threadContext"></param>
+               private void Execute(Object threadContext)
+               {
+                       TTransport client = (TTransport)threadContext;
+                       TTransport inputTransport = null;
+                       TTransport outputTransport = null;
+                       TProtocol inputProtocol = null;
+                       TProtocol outputProtocol = null;
+                       try
+                       {
+                               inputTransport = inputTransportFactory.GetTransport(client);
+                               outputTransport = outputTransportFactory.GetTransport(client);
+                               inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                               outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+                               while (processor.Process(inputProtocol, outputProtocol)) 
+                               {
+                                       //keep processing requests until client disconnects
+                               }
+                       }
+                       catch (TTransportException ttx)
+                       {
+                               // Assume the client died and continue silently
+                       }
+                       
+                       catch (Exception x)
+                       {
+                               Console.Error.WriteLine("Error: " + x);
+                       }
+
+                       if (inputTransport != null)
+                       {
+                               inputTransport.Close();
+                       }
+                       if (outputTransport != null)
+                       {
+                               outputTransport.Close();
+                       }
+               }
+       }
+}
diff --git a/lib/csharp/src/TApplicationException.cs b/lib/csharp/src/TApplicationException.cs
new file mode 100644 (file)
index 0000000..e4f3acf
--- /dev/null
@@ -0,0 +1,127 @@
+//
+//  TApplicationException.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+       public class TApplicationException : Exception
+       {
+               protected ExceptionType type;
+
+               public TApplicationException()
+               {
+               }
+
+               public TApplicationException(ExceptionType type)
+               {
+                       this.type = type;
+               }
+
+               public TApplicationException(ExceptionType type, string message)
+                       : base(message)
+               {
+                       this.type = type;
+               }
+
+               public static TApplicationException Read(TProtocol iprot)
+               {
+                       TField field;
+                       TStruct struc = iprot.ReadStructBegin();
+
+                       string message = null;
+                       ExceptionType type = ExceptionType.Unknown;
+
+                       while (true)
+                       {
+                               field = iprot.ReadFieldBegin();
+                               if (field.Type == TType.Stop)
+                               {
+                                       break;
+                               }
+
+                               switch (field.ID)
+                               {
+                                       case 1:
+                                               if (field.Type == TType.String)
+                                               {
+                                                       message = iprot.ReadString();
+                                               }
+                                               else
+                                               {
+                                                       TProtocolUtil.Skip(iprot, field.Type);
+                                               }
+                                               break;
+                                       case 2:
+                                               if (field.Type == TType.I32)
+                                               {
+                                                       type = (ExceptionType)iprot.ReadI32();
+                                               }
+                                               else
+                                               {
+                                                       TProtocolUtil.Skip(iprot, field.Type);
+                                               }
+                                               break;
+                                       default:
+                                               TProtocolUtil.Skip(iprot, field.Type);
+                                               break;
+                               }
+
+                               iprot.ReadFieldEnd();
+                       }
+
+                       iprot.ReadStructEnd();
+
+                       return new TApplicationException(type, message);
+               }
+
+               public void Write(TProtocol oprot)
+               {
+                       TStruct struc = new TStruct("TApplicationException");
+                       TField field = new TField();
+
+                       oprot.WriteStructBegin(struc);
+
+                       if (!String.IsNullOrEmpty(Message))
+                       {
+                               field.Name = "message";
+                               field.Type = TType.String;
+                               field.ID = 1;
+                               oprot.WriteFieldBegin(field);
+                               oprot.WriteString(Message);
+                               oprot.WriteFieldEnd();
+                       }
+
+                       field.Name = "type";
+                       field.Type = TType.I32;
+                       field.ID = 2;
+                       oprot.WriteFieldBegin(field);
+                       oprot.WriteI32((int)type);
+                       oprot.WriteFieldEnd();
+                       oprot.WriteFieldStop();
+                       oprot.WriteStructEnd();
+               }
+
+               public enum ExceptionType
+               {
+                       Unknown,
+                       UnknownMethod,
+                       InvalidMessageType,
+                       WrongMethodName,
+                       BadSequenceID,
+                       MissingResult
+               }
+       }
+}
diff --git a/lib/csharp/src/TProcessor.cs b/lib/csharp/src/TProcessor.cs
new file mode 100644 (file)
index 0000000..7567820
--- /dev/null
@@ -0,0 +1,24 @@
+//
+//  TProcessor.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Distributed under the Thrift Software License
+//
+//  See accompanying file LICENSE or visit the Thrift site at:
+//  http://developers.facebook.com/thrift/using
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+       public interface TProcessor
+       {
+               bool Process(TProtocol iprot, TProtocol oprot);
+       }
+}
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
new file mode 100644 (file)
index 0000000..4b407b1
--- /dev/null
@@ -0,0 +1,79 @@
+\feff<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</ProjectGuid>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <OutputType>Library</OutputType>
+    <NoStandardLibraries>false</NoStandardLibraries>
+    <AssemblyName>Thrift</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <RootNamespace>Thrift</RootNamespace>
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Xml.Linq" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Protocol\TBinaryProtocol.cs" />
+    <Compile Include="Protocol\TField.cs" />
+    <Compile Include="Protocol\TList.cs" />
+    <Compile Include="Protocol\TMap.cs" />
+    <Compile Include="Protocol\TMessage.cs" />
+    <Compile Include="Protocol\TMessageType.cs" />
+    <Compile Include="Protocol\TProtocol.cs" />
+    <Compile Include="Protocol\TProtocolException.cs" />
+    <Compile Include="Protocol\TProtocolFactory.cs" />
+    <Compile Include="Protocol\TProtocolUtil.cs" />
+    <Compile Include="Protocol\TSet.cs" />
+    <Compile Include="Protocol\TStruct.cs" />
+    <Compile Include="Protocol\TType.cs" />
+    <Compile Include="Server\TServer.cs" />
+    <Compile Include="Server\TSimpleServer.cs" />
+    <Compile Include="Server\TThreadPoolServer.cs" />
+    <Compile Include="TApplicationException.cs" />
+    <Compile Include="TProcessor.cs" />
+    <Compile Include="Transport\TServerSocket.cs" />
+    <Compile Include="Transport\TServerTransport.cs" />
+    <Compile Include="Transport\TSocket.cs" />
+    <Compile Include="Transport\TStreamTransport.cs" />
+    <Compile Include="Transport\TTransport.cs" />
+    <Compile Include="Transport\TTransportException.cs" />
+    <Compile Include="Transport\TTransportFactory.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+  <ProjectExtensions>
+    <VisualStudio AllowExistingFolder="true" />
+  </ProjectExtensions>
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.sln b/lib/csharp/src/Thrift.sln
new file mode 100644 (file)
index 0000000..cb7342c
--- /dev/null
@@ -0,0 +1,51 @@
+\feff
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "..\..\..\test\csharp\ThriftTest\ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}"
+       ProjectSection(ProjectDependencies) = postProject
+               {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+       EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftMSBuildTask", "..\ThriftMSBuildTask\ThriftMSBuildTask.csproj", "{EC0A0231-66EA-4593-A792-C6CA3BB8668E}"
+EndProject
+Global
+       GlobalSection(SourceCodeControl) = preSolution
+               SccNumberOfProjects = 4
+               SccProjectName0 = Perforce\u0020Project
+               SccLocalPath0 = ..\\..\\..
+               SccProvider0 = MSSCCI:Perforce\u0020SCM
+               SccProjectFilePathRelativizedFromConnection0 = lib\\csharp\\src\\
+               SccProjectUniqueName1 = Thrift.csproj
+               SccLocalPath1 = ..\\..\\..
+               SccProjectFilePathRelativizedFromConnection1 = lib\\csharp\\src\\
+               SccProjectUniqueName2 = ..\\..\\..\\test\\csharp\\ThriftTest\\ThriftTest.csproj
+               SccLocalPath2 = ..\\..\\..
+               SccProjectFilePathRelativizedFromConnection2 = test\\csharp\\ThriftTest\\
+               SccProjectUniqueName3 = ..\\ThriftMSBuildTask\\ThriftMSBuildTask.csproj
+               SccLocalPath3 = ..\\..\\..
+               SccProjectFilePathRelativizedFromConnection3 = lib\\csharp\\ThriftMSBuildTask\\
+       EndGlobalSection
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+               {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.Build.0 = Release|Any CPU
+               {EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs
new file mode 100644 (file)
index 0000000..cb4a84f
--- /dev/null
@@ -0,0 +1,131 @@
+//
+//  TServerTransport.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Net.Sockets;
+
+
+namespace Thrift.Transport
+{
+       public class TServerSocket : TServerTransport
+       {
+               /**
+               * Underlying server with socket
+               */
+               private TcpListener server = null;
+
+               /**
+                * Port to listen on
+                */
+               private int port = 0;
+
+               /**
+                * Timeout for client sockets from accept
+                */
+               private int clientTimeout = 0;
+
+               /**
+                * Creates a server socket from underlying socket object
+                */
+               public TServerSocket(TcpListener listener)
+                       :this(listener, 0)
+               {
+               }
+
+               /**
+                * Creates a server socket from underlying socket object
+                */
+               public TServerSocket(TcpListener listener, int clientTimeout)
+               {
+                       this.server = listener;
+                       this.clientTimeout = clientTimeout;
+               }
+
+               /**
+                * Creates just a port listening server socket
+                */
+               public TServerSocket(int port)
+                       : this(port, 0)
+               {
+               }
+
+               /**
+                * Creates just a port listening server socket
+                */
+               public TServerSocket(int port, int clientTimeout)
+               {
+                       this.port = port;
+                       this.clientTimeout = clientTimeout;
+                       try
+                       {
+                               // Make server socket
+                               server = new TcpListener(System.Net.IPAddress.Any, this.port);
+                       }
+                       catch (Exception e)
+                       {
+                               server = null;
+                               throw new TTransportException("Could not create ServerSocket on port " + port + ".");
+                       }
+               }
+
+               public override void Listen()
+               {
+                       // Make sure not to block on accept
+                       if (server != null)
+                       {
+                               try
+                               {
+                                       server.Start();
+                               }
+                               catch (SocketException sx)
+                               {
+                                       Console.Error.WriteLine(sx);
+                               }
+                       }
+               }
+
+               protected override TTransport AcceptImpl()
+               {
+                       if (server == null)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+                       }
+                       try
+                       {
+                               TcpClient result = server.AcceptTcpClient();
+                               TSocket result2 = new TSocket(result);
+                               result2.Timeout = clientTimeout;
+                               return result2;
+                       }
+                       catch (Exception ex)
+                       {
+                               throw new TTransportException(ex.ToString());
+                       }
+               }
+
+               public override void Close()
+               {
+                       if (server != null)
+                       {
+                               try
+                               {
+                                       server.Stop();
+                               }
+                               catch (Exception ex)
+                               {
+                                       Console.Error.WriteLine("WARNING: Could not close server socket: " + ex);
+                               }
+                               server = null;
+                       }
+               }
+       }
+}
diff --git a/lib/csharp/src/Transport/TServerTransport.cs b/lib/csharp/src/Transport/TServerTransport.cs
new file mode 100644 (file)
index 0000000..b4f5f07
--- /dev/null
@@ -0,0 +1,31 @@
+//
+//  TServerTransport.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Transport
+{
+       public abstract class TServerTransport
+       {
+               public abstract void Listen();
+               public abstract void Close();
+               protected abstract TTransport AcceptImpl();
+
+               public TTransport Accept()
+               {
+                       TTransport transport = AcceptImpl();
+                       if (transport == null) {
+                         throw new TTransportException("accept() may not return NULL");
+                       }
+                       return transport;
+                }
+       }
+}
diff --git a/lib/csharp/src/Transport/TSocket.cs b/lib/csharp/src/Transport/TSocket.cs
new file mode 100644 (file)
index 0000000..c05d587
--- /dev/null
@@ -0,0 +1,122 @@
+//
+//  TSocket.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Net.Sockets;
+
+namespace Thrift.Transport
+{
+       public class TSocket : TStreamTransport
+       {
+               private TcpClient client = null;
+               private string host = null;
+               private int port = 0;
+               private int timeout = 0;
+
+               public TSocket(TcpClient client)
+               {
+                       this.client = client;
+
+                       if (IsOpen)
+                       {
+                               inputStream = client.GetStream();
+                               outputStream = client.GetStream();
+                       }
+               }
+
+               public TSocket(string host, int port) : this(host, port, 0)
+               {
+               }
+
+               public TSocket(string host, int port, int timeout)
+               {
+                       this.host = host;
+                       this.port = port;
+                       this.timeout = timeout;
+
+                       InitSocket();
+               }
+
+               private void InitSocket()
+               {
+                       client = new TcpClient();
+                       client.ReceiveTimeout = client.SendTimeout = timeout;
+               }
+
+               public int Timeout
+               {
+                       set
+                       {
+                               client.ReceiveTimeout = client.SendTimeout = timeout = value;
+                       }
+               }
+
+               public TcpClient TcpClient
+               {
+                       get
+                       {
+                               return client;
+                       }
+               }
+
+               public override bool IsOpen
+               {
+                       get
+                       {
+                               if (client == null)
+                               {
+                                       return false;
+                               }
+
+                               return client.Connected;
+                       }
+               }
+
+               public override void Open()
+               {
+                       if (IsOpen)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+                       }
+
+                       if (String.IsNullOrEmpty(host))
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+                       }
+
+                       if (port <= 0)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+                       }
+
+                       if (client == null)
+                       {
+                               InitSocket();
+                       }
+
+                       client.Connect(host, port);
+                       inputStream = client.GetStream();
+                       outputStream = client.GetStream();
+               }
+
+               public override void Close()
+               {
+                       base.Close();
+                       if (client != null)
+                       {
+                               client.Close();
+                               client = null;
+                       }
+               }
+       }
+}
diff --git a/lib/csharp/src/Transport/TStreamTransport.cs b/lib/csharp/src/Transport/TStreamTransport.cs
new file mode 100644 (file)
index 0000000..1715b6a
--- /dev/null
@@ -0,0 +1,87 @@
+//
+//  TStreamTransport.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Thrift.Transport
+{
+       public class TStreamTransport : TTransport
+       {
+               protected Stream inputStream;
+               protected Stream outputStream;
+
+               public TStreamTransport()
+               {
+               }
+
+               public TStreamTransport(Stream inputStream, Stream outputStream)
+               {
+                       this.inputStream = inputStream;
+                       this.outputStream = outputStream;
+               }
+
+               public override bool IsOpen
+               {
+                       get { return true; }
+               }
+
+               public override void Open()
+               {
+               }
+
+               public override void Close()
+               {
+                       if (inputStream != null)
+                       {
+                               inputStream.Close();
+                               inputStream = null;
+                       }
+                       if (outputStream != null)
+                       {
+                               outputStream.Close();
+                               outputStream = null;
+                       }
+               }
+
+               public override int Read(byte[] buf, int off, int len)
+               {
+                       if (inputStream == null)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot read from null inputstream");
+                       }
+
+                       return inputStream.Read(buf, off, len);
+               }
+
+               public override void Write(byte[] buf, int off, int len)
+               {
+                       if (outputStream == null)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
+                       }
+
+                       outputStream.Write(buf, off, len);
+               }
+
+               public override void Flush()
+               {
+                       if (outputStream == null)
+                       {
+                               throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot flush null outputstream");
+                       }
+
+                       outputStream.Flush();
+               }
+       }
+}
diff --git a/lib/csharp/src/Transport/TTransport.cs b/lib/csharp/src/Transport/TTransport.cs
new file mode 100644 (file)
index 0000000..90f7e74
--- /dev/null
@@ -0,0 +1,60 @@
+//
+//  TTransport.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Transport
+{
+       public abstract class TTransport
+       {
+               public abstract bool IsOpen
+               {
+                       get;
+               }
+
+               public bool Peek()
+               {
+                       return IsOpen;
+               }
+
+               public abstract void Open();
+
+               public abstract void Close();
+
+               public abstract int Read(byte[] buf, int off, int len);
+
+               public int ReadAll(byte[] buf, int off, int len)
+               {
+                       int got = 0;
+                       int ret = 0;
+
+                       while (got < len)
+                       {
+                               ret = Read(buf, off + got, len - got);
+                               if (ret <= 0)
+                               {
+                                       throw new TTransportException("Cannot read, Remote side has closed");
+                               }
+                               got += ret;
+                       }
+
+                       return got;
+               }
+
+               public abstract void Write(byte[] buf, int off, int len);
+
+               public virtual void Flush()
+               {
+               }
+       }
+}
diff --git a/lib/csharp/src/Transport/TTransportException.cs b/lib/csharp/src/Transport/TTransportException.cs
new file mode 100644 (file)
index 0000000..d59c46e
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  TTransportException.cs
+//
+//  Begin:  Aug 19, 2007
+//  Authors: 
+//             Todd Berman <tberman@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Transport
+{
+       public class TTransportException : Exception
+       {
+               protected ExceptionType type;
+
+               public TTransportException()
+                       : base()
+               {
+               }
+
+               public TTransportException(ExceptionType type)
+                       : this()
+               {
+                       this.type = type;
+               }
+
+               public TTransportException(ExceptionType type, string message)
+                       : base(message)
+               {
+                       this.type = type;
+               }
+
+               public TTransportException(string message)
+                       : base(message)
+               {
+               }
+
+               public ExceptionType Type
+               {
+                       get { return type; }
+               }
+
+               public enum ExceptionType
+               {
+                       Unknown,
+                       NotOpen,
+                       AlreadyOpen,
+                       TimedOut,
+                       EndOfFile
+               }
+       }
+}
diff --git a/lib/csharp/src/Transport/TTransportFactory.cs b/lib/csharp/src/Transport/TTransportFactory.cs
new file mode 100644 (file)
index 0000000..456140d
--- /dev/null
@@ -0,0 +1,32 @@
+//
+//  TTransportFactory.cs
+//
+//  Begin:  Dec 3, 2007
+//  Authors: 
+//             Will Palmeri <wpalmeri@imeem.com>
+//
+//  Copyright (C) 2007 imeem, inc. <http://www.imeem.com>
+//  All rights reserved.
+//
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+
+namespace Thrift.Transport
+{
+       /// <summary>
+       /// From Mark Slee & Aditya Agarwal of Facebook:
+       /// Factory class used to create wrapped instance of Transports.
+       /// This is used primarily in servers, which get Transports from
+       /// a ServerTransport and then may want to mutate them (i.e. create
+       /// a BufferedTransport from the underlying base transport)
+       /// </summary>
+       public class TTransportFactory
+       {
+               public TTransport GetTransport(TTransport trans)
+               {
+                       return trans;
+               }
+       }
+}
index fd0ac97..8c91cb7 100644 (file)
@@ -2,6 +2,7 @@ java_package thrift.test
 cpp_namespace thrift.test
 ruby_namespace Thrift.Test
 perl_package ThriftTest
+csharp_namespace Thrift.Test
 
 enum Numberz
 {
index 2e79051..cff0589 100644 (file)
--- a/thrift.el
+++ b/thrift.el
@@ -10,7 +10,7 @@
 (defconst thrift-font-lock-keywords
   (list
    '("#.*$" . font-lock-comment-face)  ;; perl style comments
-   '("\\<\\(include\\|struct\\|exception\\|typedef\\|cpp_namespace\\|java_package\\|cocoa_prefix\\|php_namespace\\|ruby_namespace\\|py_module\\|perl_package\\|const\\|enum\\|service\\|extends\\|void\\|async\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face)  ;; keywords
+   '("\\<\\(include\\|struct\\|exception\\|typedef\\|cpp_namespace\\|java_package\\|cocoa_prefix\\|csharp_namespace\\|php_namespace\\|ruby_namespace\\|py_module\\|perl_package\\|smalltalk_category\\|smalltalk_prefix\\|const\\|enum\\|service\\|extends\\|void\\|async\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face)  ;; keywords
    '("\\<\\(bool\\|byte\\|i16\\|i32\\|i64\\|double\\|string\\|binary\\|map\\|list\\|set\\)\\>" . font-lock-type-face)  ;; built-in types
    '("\\<\\([0-9]+\\)\\>" . font-lock-variable-name-face)   ;; ordinals
    '("\\<\\(\\w+\\)\\s-*(" (1 font-lock-function-name-face))  ;; functions
index d6727fb..83e7403 100644 (file)
@@ -31,7 +31,8 @@ syn match thriftNumber "-\=\<\d\+\>" contained
 
 " Keywords
 syn keyword thriftKeyword namespace cpp_namespace java_package cocoa_prefix
-syn keyword php_namespace ruby_namespace py_module perl_package
+syn keyword thriftKeyword csharp_namespace smalltalk_category smalltalk_prefix
+syn keyword thriftKeyword php_namespace ruby_namespace py_module perl_package
 syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_namespace xsd_attrs
 syn keyword thriftKeyword include cpp_include cpp_type const optional required
 syn keyword thriftBasicTypes void bool byte i16 i32 i64 double string binary