You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2021/02/11 21:19:34 UTC
[thrift] branch master updated (897652e -> 876aee5)
This is an automated email from the ASF dual-hosted git repository.
jensg pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git.
from 897652e THRIFT-5348: Update debian/copyright [skip ci] Patch: Jihoon Seo
new b89316d Revert "THRIFT-4982 Remove deprecated C# bindings from the code base"
new 876aee5 Setup for Visual Studio 2019 + workarounds for some open tickets: - (NO TICKET) fix Haxe warning - Referenzdaten PerfTest Delphi und netstd - "custom build" added to version info - netstd nuget upgrades
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.gitignore | 17 +
compiler/cpp/CMakeLists.txt | 1 +
compiler/cpp/Makefile.am | 1 +
compiler/cpp/compiler.vcxproj | 9 +-
compiler/cpp/compiler.vcxproj.filters | 3 +
.../cpp/src/thrift/generate/t_csharp_generator.cc | 3259 ++++++++++++++++++++
compiler/cpp/src/thrift/generate/t_generator.cc | 5 +-
compiler/cpp/src/thrift/main.cc | 2 +-
compiler/cpp/src/thrift/thriftl.ll | 1 +
compiler/cpp/tests/CMakeLists.txt | 1 +
lib/csharp/Makefile.am | 114 +
lib/csharp/README.md | 32 +
.../ThriftMSBuildTask/Properties/AssemblyInfo.cs | 60 +
lib/csharp/ThriftMSBuildTask/ThriftBuild.cs | 246 ++
.../ThriftMSBuildTask/ThriftMSBuildTask.csproj | 118 +
lib/csharp/coding_standards.md | 6 +
lib/csharp/src/Collections/TCollections.cs | 94 +
lib/csharp/src/Collections/THashSet.cs | 160 +
lib/csharp/src/Net35/ExtensionsNet35.cs | 31 +
lib/csharp/src/Properties/AssemblyInfo.cs | 55 +
lib/csharp/src/Protocol/TAbstractBase.cs | 29 +
lib/csharp/src/Protocol/TBase.cs | 29 +
lib/csharp/src/Protocol/TBase64Utils.cs | 100 +
lib/csharp/src/Protocol/TBinaryProtocol.cs | 395 +++
lib/csharp/src/Protocol/TCompactProtocol.cs | 849 +++++
lib/csharp/src/Protocol/TField.cs | 62 +
lib/csharp/src/Protocol/TJSONProtocol.cs | 1124 +++++++
lib/csharp/src/Protocol/TList.cs | 54 +
lib/csharp/src/Protocol/TMap.cs | 62 +
lib/csharp/src/Protocol/TMessage.cs | 62 +
lib/csharp/src/Protocol/TMessageType.cs | 31 +
lib/csharp/src/Protocol/TMultiplexedProcessor.cs | 183 ++
lib/csharp/src/Protocol/TMultiplexedProtocol.cs | 103 +
lib/csharp/src/Protocol/TProtocol.cs | 142 +
lib/csharp/src/Protocol/TProtocolDecorator.cs | 261 ++
lib/csharp/src/Protocol/TProtocolException.cs | 67 +
lib/csharp/src/Protocol/TProtocolFactory.cs | 33 +
lib/csharp/src/Protocol/TProtocolUtil.cs | 108 +
lib/csharp/src/Protocol/TSet.cs | 59 +
lib/csharp/src/Protocol/TStruct.cs | 46 +
lib/csharp/src/Protocol/TType.cs | 44 +
lib/csharp/src/Server/TServer.cs | 155 +
lib/csharp/src/Server/TServerEventHandler.cs | 53 +
lib/csharp/src/Server/TSimpleServer.cs | 180 ++
lib/csharp/src/Server/TThreadPoolServer.cs | 295 ++
lib/csharp/src/Server/TThreadedServer.cs | 282 ++
lib/csharp/src/TApplicationException.cs | 146 +
lib/csharp/src/TAsyncProcessor.cs | 38 +
lib/csharp/src/TControllingHandler.cs | 29 +
lib/csharp/src/TException.cs | 40 +
lib/csharp/src/TProcessor.cs | 33 +
lib/csharp/src/TProcessorFactory.cs | 30 +
lib/csharp/src/TPrototypeProcessorFactory.cs | 55 +
lib/csharp/src/TSingletonProcessorFactory.cs | 43 +
lib/csharp/src/Thrift.45.csproj | 138 +
lib/csharp/src/Thrift.csproj | 166 +
lib/csharp/src/Thrift.sln | 47 +
lib/csharp/src/Transport/TBufferedTransport.cs | 194 ++
lib/csharp/src/Transport/TFramedTransport.cs | 205 ++
lib/csharp/src/Transport/THttpClient.cs | 486 +++
lib/csharp/src/Transport/THttpHandler.cs | 102 +
lib/csharp/src/Transport/THttpTaskAsyncHandler.cs | 97 +
lib/csharp/src/Transport/TMemoryBuffer.cs | 117 +
.../src/Transport/TNamedPipeClientTransport.cs | 111 +
.../src/Transport/TNamedPipeServerTransport.cs | 296 ++
lib/csharp/src/Transport/TServerSocket.cs | 176 ++
lib/csharp/src/Transport/TServerTransport.cs | 44 +
lib/csharp/src/Transport/TSilverlightSocket.cs | 393 +++
lib/csharp/src/Transport/TSocket.cs | 245 ++
lib/csharp/src/Transport/TSocketVersionizer.cs | 78 +
lib/csharp/src/Transport/TStreamTransport.cs | 128 +
lib/csharp/src/Transport/TTLSServerSocket.cs | 223 ++
lib/csharp/src/Transport/TTLSSocket.cs | 445 +++
lib/csharp/src/Transport/TTransport.cs | 146 +
lib/csharp/src/Transport/TTransportException.cs | 69 +
lib/csharp/src/Transport/TTransportFactory.cs | 42 +
lib/{netstd/Thrift => csharp/src}/thrift.snk | Bin
lib/csharp/test/JSON/JSONTest.csproj | 85 +
lib/csharp/test/JSON/Program.cs | 95 +
lib/csharp/test/JSON/Properties/AssemblyInfo.cs | 55 +
lib/csharp/test/JSON/app.config | 21 +
.../test/Multiplex/Client/Multiplex.Test.Client.cs | 82 +
.../test/Multiplex/Client/MultiplexClient.csproj | 148 +
.../Multiplex/Client/Properties/AssemblyInfo.cs | 55 +
lib/csharp/test/Multiplex/Makefile.am | 63 +
lib/csharp/test/Multiplex/Multiplex.Test.Common.cs | 40 +
.../test/Multiplex/Server/Multiplex.Test.Server.cs | 107 +
.../test/Multiplex/Server/MultiplexServer.csproj | 148 +
.../Multiplex/Server/Properties/AssemblyInfo.cs | 55 +
.../test/ThriftMVCTest/App_Start/FilterConfig.cs | 31 +
.../test/ThriftMVCTest/App_Start/RouteConfig.cs | 39 +
lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs | 32 +
.../ThriftMVCTest/Controllers/HomeController.cs | 70 +
lib/csharp/test/ThriftMVCTest/Global.asax | 19 +
lib/csharp/test/ThriftMVCTest/Global.asax.cs | 34 +
.../test/ThriftMVCTest/Properties/AssemblyInfo.cs | 53 +
lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs | 37 +
lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs | 32 +
lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj | 200 ++
.../test/ThriftMVCTest/Views/Home/Index.cshtml | 25 +
.../test/ThriftMVCTest/Views/Shared/_Layout.cshtml | 30 +
lib/csharp/test/ThriftMVCTest/Views/Web.config | 60 +
.../test/ThriftMVCTest/Views/_ViewStart.cshtml | 22 +
lib/csharp/test/ThriftMVCTest/Web.Debug.config | 45 +
lib/csharp/test/ThriftMVCTest/Web.Release.config | 46 +
lib/csharp/test/ThriftMVCTest/Web.config | 92 +
lib/csharp/test/ThriftMVCTest/favicon.ico | Bin 0 -> 32038 bytes
lib/csharp/test/ThriftMVCTest/packages.config | 25 +
lib/delphi/Thrift.groupproj | 120 +
lib/delphi/Thrift.groupproj.local | 9 +
lib/delphi/test/Performance/Referenz.txt | 21 +
.../Thrift.Benchmarks/Thrift.Benchmarks.csproj | 2 +-
.../Thrift.IntegrationTests.csproj | 8 +-
lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj | 10 +-
lib/netstd/Thrift/Thrift.csproj | 16 +-
test/ThriftTest.thrift | 1 +
test/csharp/Makefile.am | 95 +
test/csharp/Program.cs | 71 +
test/csharp/Properties/AssemblyInfo.cs | 55 +
test/csharp/TestClient.cs | 870 ++++++
test/csharp/TestServer.cs | 535 ++++
test/csharp/ThriftTest.csproj | 141 +
test/csharp/ThriftTest.sln | 17 +
test/haxe/src/Arguments.hx | 2 +-
test/netstd/Client/Client.csproj | 2 +-
test/netstd/Referenz.txt | 20 +
test/netstd/Server/Server.csproj | 2 +-
test/netstd/ThriftTest.sln | 63 +-
tutorial/csharp/CsharpClient/CsharpClient.cs | 92 +
tutorial/csharp/CsharpClient/CsharpClient.csproj | 110 +
.../csharp/CsharpClient/Properties/AssemblyInfo.cs | 55 +
tutorial/csharp/CsharpServer/CsharpServer.cs | 129 +
tutorial/csharp/CsharpServer/CsharpServer.csproj | 111 +
.../csharp/CsharpServer/Properties/AssemblyInfo.cs | 55 +
tutorial/csharp/tutorial.sln | 39 +
tutorial/netstd/Client/Client.csproj | 2 +-
tutorial/netstd/Server/Server.csproj | 2 +-
137 files changed, 17857 insertions(+), 29 deletions(-)
create mode 100644 compiler/cpp/src/thrift/generate/t_csharp_generator.cc
create mode 100644 lib/csharp/Makefile.am
create mode 100644 lib/csharp/README.md
create mode 100644 lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
create mode 100644 lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
create mode 100644 lib/csharp/coding_standards.md
create mode 100644 lib/csharp/src/Collections/TCollections.cs
create mode 100644 lib/csharp/src/Collections/THashSet.cs
create mode 100644 lib/csharp/src/Net35/ExtensionsNet35.cs
create mode 100644 lib/csharp/src/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/src/Protocol/TAbstractBase.cs
create mode 100644 lib/csharp/src/Protocol/TBase.cs
create mode 100644 lib/csharp/src/Protocol/TBase64Utils.cs
create mode 100644 lib/csharp/src/Protocol/TBinaryProtocol.cs
create mode 100644 lib/csharp/src/Protocol/TCompactProtocol.cs
create mode 100644 lib/csharp/src/Protocol/TField.cs
create mode 100644 lib/csharp/src/Protocol/TJSONProtocol.cs
create mode 100644 lib/csharp/src/Protocol/TList.cs
create mode 100644 lib/csharp/src/Protocol/TMap.cs
create mode 100644 lib/csharp/src/Protocol/TMessage.cs
create mode 100644 lib/csharp/src/Protocol/TMessageType.cs
create mode 100644 lib/csharp/src/Protocol/TMultiplexedProcessor.cs
create mode 100644 lib/csharp/src/Protocol/TMultiplexedProtocol.cs
create mode 100644 lib/csharp/src/Protocol/TProtocol.cs
create mode 100644 lib/csharp/src/Protocol/TProtocolDecorator.cs
create mode 100644 lib/csharp/src/Protocol/TProtocolException.cs
create mode 100644 lib/csharp/src/Protocol/TProtocolFactory.cs
create mode 100644 lib/csharp/src/Protocol/TProtocolUtil.cs
create mode 100644 lib/csharp/src/Protocol/TSet.cs
create mode 100644 lib/csharp/src/Protocol/TStruct.cs
create mode 100644 lib/csharp/src/Protocol/TType.cs
create mode 100644 lib/csharp/src/Server/TServer.cs
create mode 100644 lib/csharp/src/Server/TServerEventHandler.cs
create mode 100644 lib/csharp/src/Server/TSimpleServer.cs
create mode 100644 lib/csharp/src/Server/TThreadPoolServer.cs
create mode 100644 lib/csharp/src/Server/TThreadedServer.cs
create mode 100644 lib/csharp/src/TApplicationException.cs
create mode 100644 lib/csharp/src/TAsyncProcessor.cs
create mode 100644 lib/csharp/src/TControllingHandler.cs
create mode 100644 lib/csharp/src/TException.cs
create mode 100644 lib/csharp/src/TProcessor.cs
create mode 100644 lib/csharp/src/TProcessorFactory.cs
create mode 100644 lib/csharp/src/TPrototypeProcessorFactory.cs
create mode 100644 lib/csharp/src/TSingletonProcessorFactory.cs
create mode 100644 lib/csharp/src/Thrift.45.csproj
create mode 100644 lib/csharp/src/Thrift.csproj
create mode 100644 lib/csharp/src/Thrift.sln
create mode 100644 lib/csharp/src/Transport/TBufferedTransport.cs
create mode 100644 lib/csharp/src/Transport/TFramedTransport.cs
create mode 100644 lib/csharp/src/Transport/THttpClient.cs
create mode 100644 lib/csharp/src/Transport/THttpHandler.cs
create mode 100644 lib/csharp/src/Transport/THttpTaskAsyncHandler.cs
create mode 100644 lib/csharp/src/Transport/TMemoryBuffer.cs
create mode 100644 lib/csharp/src/Transport/TNamedPipeClientTransport.cs
create mode 100644 lib/csharp/src/Transport/TNamedPipeServerTransport.cs
create mode 100644 lib/csharp/src/Transport/TServerSocket.cs
create mode 100644 lib/csharp/src/Transport/TServerTransport.cs
create mode 100644 lib/csharp/src/Transport/TSilverlightSocket.cs
create mode 100644 lib/csharp/src/Transport/TSocket.cs
create mode 100644 lib/csharp/src/Transport/TSocketVersionizer.cs
create mode 100644 lib/csharp/src/Transport/TStreamTransport.cs
create mode 100644 lib/csharp/src/Transport/TTLSServerSocket.cs
create mode 100644 lib/csharp/src/Transport/TTLSSocket.cs
create mode 100644 lib/csharp/src/Transport/TTransport.cs
create mode 100644 lib/csharp/src/Transport/TTransportException.cs
create mode 100644 lib/csharp/src/Transport/TTransportFactory.cs
copy lib/{netstd/Thrift => csharp/src}/thrift.snk (100%)
create mode 100644 lib/csharp/test/JSON/JSONTest.csproj
create mode 100644 lib/csharp/test/JSON/Program.cs
create mode 100644 lib/csharp/test/JSON/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/test/JSON/app.config
create mode 100644 lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
create mode 100644 lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
create mode 100644 lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/test/Multiplex/Makefile.am
create mode 100644 lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
create mode 100644 lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
create mode 100644 lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
create mode 100644 lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/Global.asax
create mode 100644 lib/csharp/test/ThriftMVCTest/Global.asax.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs
create mode 100644 lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj
create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml
create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml
create mode 100644 lib/csharp/test/ThriftMVCTest/Views/Web.config
create mode 100644 lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml
create mode 100644 lib/csharp/test/ThriftMVCTest/Web.Debug.config
create mode 100644 lib/csharp/test/ThriftMVCTest/Web.Release.config
create mode 100644 lib/csharp/test/ThriftMVCTest/Web.config
create mode 100644 lib/csharp/test/ThriftMVCTest/favicon.ico
create mode 100644 lib/csharp/test/ThriftMVCTest/packages.config
create mode 100644 lib/delphi/Thrift.groupproj
create mode 100644 lib/delphi/Thrift.groupproj.local
create mode 100644 lib/delphi/test/Performance/Referenz.txt
create mode 100644 test/csharp/Makefile.am
create mode 100644 test/csharp/Program.cs
create mode 100644 test/csharp/Properties/AssemblyInfo.cs
create mode 100644 test/csharp/TestClient.cs
create mode 100644 test/csharp/TestServer.cs
create mode 100644 test/csharp/ThriftTest.csproj
create mode 100644 test/csharp/ThriftTest.sln
create mode 100644 test/netstd/Referenz.txt
create mode 100644 tutorial/csharp/CsharpClient/CsharpClient.cs
create mode 100644 tutorial/csharp/CsharpClient/CsharpClient.csproj
create mode 100644 tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
create mode 100644 tutorial/csharp/CsharpServer/CsharpServer.cs
create mode 100644 tutorial/csharp/CsharpServer/CsharpServer.csproj
create mode 100644 tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
create mode 100644 tutorial/csharp/tutorial.sln
[thrift] 02/02: Setup for Visual Studio 2019 + workarounds for some
open tickets: - (NO TICKET) fix Haxe warning - Referenzdaten PerfTest
Delphi und netstd - "custom build" added to version info - netstd nuget
upgrades
Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jensg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git
commit 876aee506b937d64b1fb035ff65e5e52def04c04
Author: Jens Geyer <je...@apache.org>
AuthorDate: Mon Dec 29 00:54:36 2014 +0100
Setup for Visual Studio 2019 + workarounds for some open tickets:
- (NO TICKET) fix Haxe warning
- Referenzdaten PerfTest Delphi und netstd
- "custom build" added to version info
- netstd nuget upgrades
---
compiler/cpp/compiler.vcxproj | 8 +-
compiler/cpp/src/thrift/main.cc | 2 +-
lib/delphi/Thrift.groupproj | 120 +++++++++++++++++++++
lib/delphi/Thrift.groupproj.local | 9 ++
lib/delphi/test/Performance/Referenz.txt | 21 ++++
.../Thrift.Benchmarks/Thrift.Benchmarks.csproj | 2 +-
.../Thrift.IntegrationTests.csproj | 8 +-
lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj | 10 +-
lib/netstd/Thrift/Thrift.csproj | 16 +--
test/haxe/src/Arguments.hx | 2 +-
test/netstd/Client/Client.csproj | 2 +-
test/netstd/Referenz.txt | 20 ++++
test/netstd/Server/Server.csproj | 2 +-
test/netstd/ThriftTest.sln | 63 ++++++++++-
tutorial/netstd/Client/Client.csproj | 2 +-
tutorial/netstd/Server/Server.csproj | 2 +-
16 files changed, 261 insertions(+), 28 deletions(-)
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index cbcf8ea..6e2bd8a 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -99,29 +99,34 @@
<ProjectGuid>{89975A1A-F799-4556-98B8-64E30AB39A90}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>compiler</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -144,6 +149,7 @@
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath)</IncludePath>
<TargetName>thrift</TargetName>
<ExecutablePath>$(ExecutablePath);C:\Program Files (x86)\Git\bin</ExecutablePath>
+ <OutDir>E:\D\TOOLS\Thrift\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
diff --git a/compiler/cpp/src/thrift/main.cc b/compiler/cpp/src/thrift/main.cc
index 50bdcea..1ba8234 100644
--- a/compiler/cpp/src/thrift/main.cc
+++ b/compiler/cpp/src/thrift/main.cc
@@ -656,7 +656,7 @@ void error_unsupported_namespace_decl(const char* old_form, const char* new_form
* Prints the version number
*/
void version() {
- printf("Thrift version %s\n", THRIFT_VERSION);
+ printf("Thrift version %s (custom build)\n", THRIFT_VERSION);
}
/**
diff --git a/lib/delphi/Thrift.groupproj b/lib/delphi/Thrift.groupproj
new file mode 100644
index 0000000..f41f293
--- /dev/null
+++ b/lib/delphi/Thrift.groupproj
@@ -0,0 +1,120 @@
+ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{86AE16E4-18D4-4C07-B06C-491E22A26C74}</ProjectGuid>
+ </PropertyGroup>
+ <ItemGroup>
+ <Projects Include="test\client.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\server.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\multiplexed\Multiplex.Test.Client.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\multiplexed\Multiplex.Test.Server.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\serializer\TestSerializer.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\skip\skiptest_version2.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\skip\skiptest_version1.dproj">
+ <Dependencies/>
+ </Projects>
+ <Projects Include="test\typeregistry\TestTypeRegistry.dproj">
+ <Dependencies/>
+ </Projects>
+ </ItemGroup>
+ <ProjectExtensions>
+ <Borland.Personality>Default.Personality.12</Borland.Personality>
+ <Borland.ProjectType/>
+ <BorlandProject>
+ <Default.Personality/>
+ </BorlandProject>
+ </ProjectExtensions>
+ <Target Name="client">
+ <MSBuild Projects="test\client.dproj"/>
+ </Target>
+ <Target Name="client:Clean">
+ <MSBuild Projects="test\client.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="client:Make">
+ <MSBuild Projects="test\client.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="server">
+ <MSBuild Projects="test\server.dproj"/>
+ </Target>
+ <Target Name="server:Clean">
+ <MSBuild Projects="test\server.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="server:Make">
+ <MSBuild Projects="test\server.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="Multiplex_Test_Client">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj"/>
+ </Target>
+ <Target Name="Multiplex_Test_Client:Clean">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="Multiplex_Test_Client:Make">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="Multiplex_Test_Server">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj"/>
+ </Target>
+ <Target Name="Multiplex_Test_Server:Clean">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="Multiplex_Test_Server:Make">
+ <MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="TestSerializer">
+ <MSBuild Projects="test\serializer\TestSerializer.dproj"/>
+ </Target>
+ <Target Name="TestSerializer:Clean">
+ <MSBuild Projects="test\serializer\TestSerializer.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="TestSerializer:Make">
+ <MSBuild Projects="test\serializer\TestSerializer.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="skiptest_version2">
+ <MSBuild Projects="test\skip\skiptest_version2.dproj"/>
+ </Target>
+ <Target Name="skiptest_version2:Clean">
+ <MSBuild Projects="test\skip\skiptest_version2.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="skiptest_version2:Make">
+ <MSBuild Projects="test\skip\skiptest_version2.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="skiptest_version1">
+ <MSBuild Projects="test\skip\skiptest_version1.dproj"/>
+ </Target>
+ <Target Name="skiptest_version1:Clean">
+ <MSBuild Projects="test\skip\skiptest_version1.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="skiptest_version1:Make">
+ <MSBuild Projects="test\skip\skiptest_version1.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="TestTypeRegistry">
+ <MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj"/>
+ </Target>
+ <Target Name="TestTypeRegistry:Clean">
+ <MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj" Targets="Clean"/>
+ </Target>
+ <Target Name="TestTypeRegistry:Make">
+ <MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj" Targets="Make"/>
+ </Target>
+ <Target Name="Build">
+ <CallTarget Targets="client;server;Multiplex_Test_Client;Multiplex_Test_Server;TestSerializer;skiptest_version2;skiptest_version1;TestTypeRegistry"/>
+ </Target>
+ <Target Name="Clean">
+ <CallTarget Targets="client:Clean;server:Clean;Multiplex_Test_Client:Clean;Multiplex_Test_Server:Clean;TestSerializer:Clean;skiptest_version2:Clean;skiptest_version1:Clean;TestTypeRegistry:Clean"/>
+ </Target>
+ <Target Name="Make">
+ <CallTarget Targets="client:Make;server:Make;Multiplex_Test_Client:Make;Multiplex_Test_Server:Make;TestSerializer:Make;skiptest_version2:Make;skiptest_version1:Make;TestTypeRegistry:Make"/>
+ </Target>
+ <Import Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')" Project="$(BDS)\Bin\CodeGear.Group.Targets"/>
+ </Project>
diff --git a/lib/delphi/Thrift.groupproj.local b/lib/delphi/Thrift.groupproj.local
new file mode 100644
index 0000000..9e6e18d
--- /dev/null
+++ b/lib/delphi/Thrift.groupproj.local
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+ <Transactions>
+ <Transaction>1899.12.30 00:00:00.000.873,E:\D\TPCPP\Thrift\wc-XE-all\wc-JensG-haxe\lib\delphi\Thrift.groupproj=C:\Users\Jens\Documents\RAD Studio\Projekte\ProjectGroup1.groupproj</Transaction>
+ </Transactions>
+ <Default.Personality>
+ <Projects ActiveProject="E:\D\TPCPP\Thrift\wc-XE-all\wc-JensG-haxe\lib\delphi\test\client.dproj"/>
+ </Default.Personality>
+</BorlandProject>
diff --git a/lib/delphi/test/Performance/Referenz.txt b/lib/delphi/test/Performance/Referenz.txt
new file mode 100644
index 0000000..53cb154
--- /dev/null
+++ b/lib/delphi/test/Performance/Referenz.txt
@@ -0,0 +1,21 @@
+Delphi TestClient 0.14.0
+Setting up for ProtocolPeformanceTest ...
+RunTest(binary): write = 2650 msec
+RunTest(binary): read = 3135 msec
+RunTest(compact): write = 2807 msec
+RunTest(compact): read = 3053 msec
+RunTest(JSON): write = 13251 msec
+RunTest(JSON): read = 18759 msec
+RunTest(binary + buffered): write = 2635 msec
+RunTest(binary + buffered): read = 3109 msec
+RunTest(compact + buffered): write = 2788 msec
+RunTest(compact + buffered): read = 3069 msec
+RunTest(JSON + buffered): write = 13604 msec
+RunTest(JSON + buffered): read = 21537 msec
+RunTest(binary + framed): write = 3019 msec
+RunTest(binary + framed): read = 3573 msec
+RunTest(compact + framed): write = 3201 msec
+RunTest(compact + framed): read = 3504 msec
+RunTest(JSON + framed): write = 15093 msec
+RunTest(JSON + framed): read = 21548 msec
+Hit ENTER ...
\ No newline at end of file
diff --git a/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj b/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
index 35138d8..740d223 100644
--- a/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
+++ b/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
@@ -25,7 +25,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
+ <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>
<ItemGroup>
diff --git a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
index 7c5639b..318757a 100644
--- a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
+++ b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
@@ -32,10 +32,10 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="CompareNETObjects" Version="4.64.0" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
- <PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
+ <PackageReference Include="CompareNETObjects" Version="4.66.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
+ <PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
+ <PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
diff --git a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
index 4b39e7d..9b54a57 100644
--- a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
+++ b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
@@ -21,11 +21,11 @@
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="CompareNETObjects" Version="4.64.0" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
- <PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
- <PackageReference Include="NSubstitute" Version="4.2.1" />
+ <PackageReference Include="CompareNETObjects" Version="4.66.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
+ <PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
+ <PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
+ <PackageReference Include="NSubstitute" Version="4.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Thrift\Thrift.csproj" />
diff --git a/lib/netstd/Thrift/Thrift.csproj b/lib/netstd/Thrift/Thrift.csproj
index 3278d98..991e64e 100644
--- a/lib/netstd/Thrift/Thrift.csproj
+++ b/lib/netstd/Thrift/Thrift.csproj
@@ -44,16 +44,16 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
- <PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0" />
- <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.0" />
- <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.0" />
- <PackageReference Include="System.IO.Pipes" Version="[4.3,)" />
+ <PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.5" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.5" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.5" />
+ <PackageReference Include="System.IO.Pipes" Version="4.3.0" />
<PackageReference Include="System.IO.Pipes.AccessControl" Version="4.5.1" />
- <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.0" />
- <PackageReference Include="System.Net.NameResolution" Version="[4.3,)" />
- <PackageReference Include="System.Net.Requests" Version="[4.3,)" />
+ <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.2" />
+ <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
+ <PackageReference Include="System.Net.Requests" Version="4.3.0" />
<PackageReference Include="System.Net.Security" Version="4.3.2" />
- <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.3" />
+ <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>
<Target Name="SetTFMAssemblyAttributesPath" BeforeTargets="GenerateTargetFrameworkMonikerAttribute">
diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx
index 56e5253..023f250 100644
--- a/test/haxe/src/Arguments.hx
+++ b/test/haxe/src/Arguments.hx
@@ -92,7 +92,7 @@ class Arguments
#if sys
private static function GetHelp() : String {
- var sProg = Path.withoutDirectory( Sys.executablePath());
+ var sProg = Path.withoutDirectory( Sys.programPath());
return "\n"
+sProg+" [client|server] [options]\n"
+"\n"
diff --git a/test/netstd/Client/Client.csproj b/test/netstd/Client/Client.csproj
index 4ed57cb..ce71809 100644
--- a/test/netstd/Client/Client.csproj
+++ b/test/netstd/Client/Client.csproj
@@ -31,7 +31,7 @@
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.0" />
+ <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.2" />
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="[4.3,)" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.7.0" />
<PackageReference Include="System.Threading" Version="[4.3,)" />
diff --git a/test/netstd/Referenz.txt b/test/netstd/Referenz.txt
new file mode 100644
index 0000000..58088e4
--- /dev/null
+++ b/test/netstd/Referenz.txt
@@ -0,0 +1,20 @@
+E:\D\TPCPP\Thrift\wc-XE-all\wc-JensG-haxe\test\netstd\Client\bin\Release\netcoreapp3.1>Client.exe --performance
+Setting up for ProtocolPeformanceTestAsync ...
+RunTestAsync(TBinaryProtocol): write = 1982 msec
+RunTestAsync(TBinaryProtocol): read = 4995 msec
+RunTestAsync(TCompactProtocol): write = 1240 msec
+RunTestAsync(TCompactProtocol): read = 3964 msec
+RunTestAsync(TJsonProtocol): write = 5206 msec
+RunTestAsync(TJsonProtocol): read = 23249 msec
+RunTestAsync(TBinaryProtocol + TBufferedTransport): write = 1990 msec
+RunTestAsync(TBinaryProtocol + TBufferedTransport): read = 5777 msec
+RunTestAsync(TCompactProtocol + TBufferedTransport): write = 1453 msec
+RunTestAsync(TCompactProtocol + TBufferedTransport): read = 4761 msec
+RunTestAsync(TJsonProtocol + TBufferedTransport): write = 8859 msec
+RunTestAsync(TJsonProtocol + TBufferedTransport): read = 30925 msec
+RunTestAsync(TBinaryProtocol + TFramedTransport): write = 2042 msec
+RunTestAsync(TBinaryProtocol + TFramedTransport): read = 5726 msec
+RunTestAsync(TCompactProtocol + TFramedTransport): write = 1480 msec
+RunTestAsync(TCompactProtocol + TFramedTransport): read = 4818 msec
+RunTestAsync(TJsonProtocol + TFramedTransport): write = 8612 msec
+RunTestAsync(TJsonProtocol + TFramedTransport): read = 30810 msec
diff --git a/test/netstd/Server/Server.csproj b/test/netstd/Server/Server.csproj
index fa5ce46..cbd0fb1 100644
--- a/test/netstd/Server/Server.csproj
+++ b/test/netstd/Server/Server.csproj
@@ -33,7 +33,7 @@
<ItemGroup>
<PackageReference Include="System.IO.Pipes" Version="4.3.0" />
<PackageReference Include="System.IO.Pipes.AccessControl" Version="4.5.1" />
- <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.0" />
+ <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.7.2" />
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="[4.3,)" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.7.0" />
<PackageReference Include="System.Threading" Version="[4.3,)" />
diff --git a/test/netstd/ThriftTest.sln b/test/netstd/ThriftTest.sln
index 352576e..7e101d9 100644
--- a/test/netstd/ThriftTest.sln
+++ b/test/netstd/ThriftTest.sln
@@ -1,6 +1,7 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26730.12
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30104.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netstd\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}"
EndProject
@@ -8,6 +9,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{0C6E8685-F191-4479-9842-882A38961127}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.IntegrationTests", "..\..\lib\netstd\Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj", "{C8148BFF-B943-4474-8D33-A641C6FD3DAB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.PublicInterfaces.Compile.Tests", "..\..\lib\netstd\Tests\Thrift.PublicInterfaces.Compile.Tests\Thrift.PublicInterfaces.Compile.Tests.csproj", "{5D86C1B6-0CDA-4D1D-80A5-240583B21148}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Tests", "..\..\lib\netstd\Tests\Thrift.Tests\Thrift.Tests.csproj", "{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Benchmarks", "..\..\lib\netstd\Benchmarks\Thrift.Benchmarks\Thrift.Benchmarks.csproj", "{66946544-8DE7-45E9-8D0E-93EADA028D44}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -54,6 +63,54 @@ Global
{0C6E8685-F191-4479-9842-882A38961127}.Release|x64.Build.0 = Release|Any CPU
{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.ActiveCfg = Release|Any CPU
{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.Build.0 = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x64.Build.0 = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x86.Build.0 = Debug|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x64.ActiveCfg = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x64.Build.0 = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x86.ActiveCfg = Release|Any CPU
+ {C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x86.Build.0 = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x64.Build.0 = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x86.Build.0 = Debug|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x64.ActiveCfg = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x64.Build.0 = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x86.ActiveCfg = Release|Any CPU
+ {5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x86.Build.0 = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x64.Build.0 = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x86.Build.0 = Debug|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x64.ActiveCfg = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x64.Build.0 = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x86.ActiveCfg = Release|Any CPU
+ {37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x86.Build.0 = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x64.Build.0 = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x86.Build.0 = Debug|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x64.ActiveCfg = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x64.Build.0 = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x86.ActiveCfg = Release|Any CPU
+ {66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/tutorial/netstd/Client/Client.csproj b/tutorial/netstd/Client/Client.csproj
index 10d5040..81b503f 100644
--- a/tutorial/netstd/Client/Client.csproj
+++ b/tutorial/netstd/Client/Client.csproj
@@ -30,7 +30,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
diff --git a/tutorial/netstd/Server/Server.csproj b/tutorial/netstd/Server/Server.csproj
index b3ff516..95eabd3 100644
--- a/tutorial/netstd/Server/Server.csproj
+++ b/tutorial/netstd/Server/Server.csproj
@@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
- <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.0" />
+ <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.4" />
</ItemGroup>
</Project>
[thrift] 01/02: Revert "THRIFT-4982 Remove deprecated C# bindings
from the code base"
Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jensg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git
commit b89316d54bb0253493b48446cb510755fb3196d2
Author: Jens Geyer <je...@apache.org>
AuthorDate: Fri Feb 28 19:22:34 2020 +0100
Revert "THRIFT-4982 Remove deprecated C# bindings from the code base"
Only compiler, test, lib and tutorial code.
---
.gitignore | 17 +
compiler/cpp/CMakeLists.txt | 1 +
compiler/cpp/Makefile.am | 1 +
compiler/cpp/compiler.vcxproj | 1 +
compiler/cpp/compiler.vcxproj.filters | 3 +
.../cpp/src/thrift/generate/t_csharp_generator.cc | 3259 ++++++++++++++++++++
compiler/cpp/src/thrift/generate/t_generator.cc | 5 +-
compiler/cpp/src/thrift/thriftl.ll | 1 +
compiler/cpp/tests/CMakeLists.txt | 1 +
lib/csharp/Makefile.am | 114 +
lib/csharp/README.md | 32 +
.../ThriftMSBuildTask/Properties/AssemblyInfo.cs | 60 +
lib/csharp/ThriftMSBuildTask/ThriftBuild.cs | 246 ++
.../ThriftMSBuildTask/ThriftMSBuildTask.csproj | 118 +
lib/csharp/coding_standards.md | 6 +
lib/csharp/src/Collections/TCollections.cs | 94 +
lib/csharp/src/Collections/THashSet.cs | 160 +
lib/csharp/src/Net35/ExtensionsNet35.cs | 31 +
lib/csharp/src/Properties/AssemblyInfo.cs | 55 +
lib/csharp/src/Protocol/TAbstractBase.cs | 29 +
lib/csharp/src/Protocol/TBase.cs | 29 +
lib/csharp/src/Protocol/TBase64Utils.cs | 100 +
lib/csharp/src/Protocol/TBinaryProtocol.cs | 395 +++
lib/csharp/src/Protocol/TCompactProtocol.cs | 849 +++++
lib/csharp/src/Protocol/TField.cs | 62 +
lib/csharp/src/Protocol/TJSONProtocol.cs | 1124 +++++++
lib/csharp/src/Protocol/TList.cs | 54 +
lib/csharp/src/Protocol/TMap.cs | 62 +
lib/csharp/src/Protocol/TMessage.cs | 62 +
lib/csharp/src/Protocol/TMessageType.cs | 31 +
lib/csharp/src/Protocol/TMultiplexedProcessor.cs | 183 ++
lib/csharp/src/Protocol/TMultiplexedProtocol.cs | 103 +
lib/csharp/src/Protocol/TProtocol.cs | 142 +
lib/csharp/src/Protocol/TProtocolDecorator.cs | 261 ++
lib/csharp/src/Protocol/TProtocolException.cs | 67 +
lib/csharp/src/Protocol/TProtocolFactory.cs | 33 +
lib/csharp/src/Protocol/TProtocolUtil.cs | 108 +
lib/csharp/src/Protocol/TSet.cs | 59 +
lib/csharp/src/Protocol/TStruct.cs | 46 +
lib/csharp/src/Protocol/TType.cs | 44 +
lib/csharp/src/Server/TServer.cs | 155 +
lib/csharp/src/Server/TServerEventHandler.cs | 53 +
lib/csharp/src/Server/TSimpleServer.cs | 180 ++
lib/csharp/src/Server/TThreadPoolServer.cs | 295 ++
lib/csharp/src/Server/TThreadedServer.cs | 282 ++
lib/csharp/src/TApplicationException.cs | 146 +
lib/csharp/src/TAsyncProcessor.cs | 38 +
lib/csharp/src/TControllingHandler.cs | 29 +
lib/csharp/src/TException.cs | 40 +
lib/csharp/src/TProcessor.cs | 33 +
lib/csharp/src/TProcessorFactory.cs | 30 +
lib/csharp/src/TPrototypeProcessorFactory.cs | 55 +
lib/csharp/src/TSingletonProcessorFactory.cs | 43 +
lib/csharp/src/Thrift.45.csproj | 138 +
lib/csharp/src/Thrift.csproj | 166 +
lib/csharp/src/Thrift.sln | 47 +
lib/csharp/src/Transport/TBufferedTransport.cs | 194 ++
lib/csharp/src/Transport/TFramedTransport.cs | 205 ++
lib/csharp/src/Transport/THttpClient.cs | 486 +++
lib/csharp/src/Transport/THttpHandler.cs | 102 +
lib/csharp/src/Transport/THttpTaskAsyncHandler.cs | 97 +
lib/csharp/src/Transport/TMemoryBuffer.cs | 117 +
.../src/Transport/TNamedPipeClientTransport.cs | 111 +
.../src/Transport/TNamedPipeServerTransport.cs | 296 ++
lib/csharp/src/Transport/TServerSocket.cs | 176 ++
lib/csharp/src/Transport/TServerTransport.cs | 44 +
lib/csharp/src/Transport/TSilverlightSocket.cs | 393 +++
lib/csharp/src/Transport/TSocket.cs | 245 ++
lib/csharp/src/Transport/TSocketVersionizer.cs | 78 +
lib/csharp/src/Transport/TStreamTransport.cs | 128 +
lib/csharp/src/Transport/TTLSServerSocket.cs | 223 ++
lib/csharp/src/Transport/TTLSSocket.cs | 445 +++
lib/csharp/src/Transport/TTransport.cs | 146 +
lib/csharp/src/Transport/TTransportException.cs | 69 +
lib/csharp/src/Transport/TTransportFactory.cs | 42 +
lib/csharp/src/thrift.snk | Bin 0 -> 596 bytes
lib/csharp/test/JSON/JSONTest.csproj | 85 +
lib/csharp/test/JSON/Program.cs | 95 +
lib/csharp/test/JSON/Properties/AssemblyInfo.cs | 55 +
lib/csharp/test/JSON/app.config | 21 +
.../test/Multiplex/Client/Multiplex.Test.Client.cs | 82 +
.../test/Multiplex/Client/MultiplexClient.csproj | 148 +
.../Multiplex/Client/Properties/AssemblyInfo.cs | 55 +
lib/csharp/test/Multiplex/Makefile.am | 63 +
lib/csharp/test/Multiplex/Multiplex.Test.Common.cs | 40 +
.../test/Multiplex/Server/Multiplex.Test.Server.cs | 107 +
.../test/Multiplex/Server/MultiplexServer.csproj | 148 +
.../Multiplex/Server/Properties/AssemblyInfo.cs | 55 +
.../test/ThriftMVCTest/App_Start/FilterConfig.cs | 31 +
.../test/ThriftMVCTest/App_Start/RouteConfig.cs | 39 +
lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs | 32 +
.../ThriftMVCTest/Controllers/HomeController.cs | 70 +
lib/csharp/test/ThriftMVCTest/Global.asax | 19 +
lib/csharp/test/ThriftMVCTest/Global.asax.cs | 34 +
.../test/ThriftMVCTest/Properties/AssemblyInfo.cs | 53 +
lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs | 37 +
lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs | 32 +
lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj | 200 ++
.../test/ThriftMVCTest/Views/Home/Index.cshtml | 25 +
.../test/ThriftMVCTest/Views/Shared/_Layout.cshtml | 30 +
lib/csharp/test/ThriftMVCTest/Views/Web.config | 60 +
.../test/ThriftMVCTest/Views/_ViewStart.cshtml | 22 +
lib/csharp/test/ThriftMVCTest/Web.Debug.config | 45 +
lib/csharp/test/ThriftMVCTest/Web.Release.config | 46 +
lib/csharp/test/ThriftMVCTest/Web.config | 92 +
lib/csharp/test/ThriftMVCTest/favicon.ico | Bin 0 -> 32038 bytes
lib/csharp/test/ThriftMVCTest/packages.config | 25 +
test/ThriftTest.thrift | 1 +
test/csharp/Makefile.am | 95 +
test/csharp/Program.cs | 71 +
test/csharp/Properties/AssemblyInfo.cs | 55 +
test/csharp/TestClient.cs | 870 ++++++
test/csharp/TestServer.cs | 535 ++++
test/csharp/ThriftTest.csproj | 141 +
test/csharp/ThriftTest.sln | 17 +
tutorial/csharp/CsharpClient/CsharpClient.cs | 92 +
tutorial/csharp/CsharpClient/CsharpClient.csproj | 110 +
.../csharp/CsharpClient/Properties/AssemblyInfo.cs | 55 +
tutorial/csharp/CsharpServer/CsharpServer.cs | 129 +
tutorial/csharp/CsharpServer/CsharpServer.csproj | 111 +
.../csharp/CsharpServer/Properties/AssemblyInfo.cs | 55 +
tutorial/csharp/tutorial.sln | 39 +
122 files changed, 17596 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index d11897e..eacff5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -184,6 +184,9 @@ project.lock.json
/lib/c_glib/test/testserialization
/lib/c_glib/thriftc.pc
/lib/c_glib/thrift_c_glib.pc
+/lib/csharp/**/bin/
+/lib/csharp/**/obj/
+/lib/csharp/src/packages
/lib/d/test/*.pem
/lib/d/libthriftd*.a
/lib/d/test/async_test
@@ -231,6 +234,8 @@ project.lock.json
/lib/js/dist
/lib/js/doc
/lib/js/test/build
+/lib/netcore/**/bin
+/lib/netcore/**/obj
/lib/netstd/**/bin
/lib/netstd/**/obj
/lib/nodejs/coverage
@@ -323,6 +328,8 @@ project.lock.json
/test/cpp/StressTestNonBlocking
/test/cpp/TestClient
/test/cpp/TestServer
+/test/csharp/obj
+/test/csharp/bin
/test/dart/**/.dart_tool
/test/dart/**/.packages
/test/dart/**/packages
@@ -351,6 +358,9 @@ project.lock.json
/test/php/php_ext_dir/
/test/py.twisted/_trial_temp/
/test/rb/Gemfile.lock
+/test/netcore/**/bin
+/test/netcore/**/obj
+/test/netcore/Thrift
/test/netstd/**/bin
/test/netstd/**/obj
/test/netstd/**/launchSettings.json
@@ -383,6 +393,10 @@ project.lock.json
/tutorial/cpp/TutorialServer
/tutorial/c_glib/tutorial_client
/tutorial/c_glib/tutorial_server
+/tutorial/csharp/CsharpServer/obj
+/tutorial/csharp/CsharpServer/bin
+/tutorial/csharp/CsharpClient/obj
+/tutorial/csharp/CsharpClient/bin
/tutorial/d/async_client
/tutorial/d/client
/tutorial/d/server
@@ -407,6 +421,9 @@ project.lock.json
/tutorial/hs/dist/
/tutorial/java/build/
/tutorial/js/build/
+/tutorial/netcore/**/bin
+/tutorial/netcore/**/obj
+/tutorial/netcore/Thrift
/tutorial/netstd/**/bin
/tutorial/netstd/**/obj
/tutorial/netstd/Interfaces
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
index 0675f0e..0d80f79 100644
--- a/compiler/cpp/CMakeLists.txt
+++ b/compiler/cpp/CMakeLists.txt
@@ -76,6 +76,7 @@ THRIFT_ADD_COMPILER(as3 "Enable compiler for ActionScript 3" ON)
THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON)
THRIFT_ADD_COMPILER(cl "Enable compiler for Common LISP" ON)
THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" ON)
+THRIFT_ADD_COMPILER(csharp "Enable compiler for C#" ON)
THRIFT_ADD_COMPILER(d "Enable compiler for D" ON)
THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" ON)
THRIFT_ADD_COMPILER(delphi "Enable compiler for Delphi" ON)
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 05c9121..2f962fe 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -73,6 +73,7 @@ thrift_SOURCES += src/thrift/generate/t_as3_generator.cc \
src/thrift/generate/t_c_glib_generator.cc \
src/thrift/generate/t_cl_generator.cc \
src/thrift/generate/t_cpp_generator.cc \
+ src/thrift/generate/t_csharp_generator.cc \
src/thrift/generate/t_d_generator.cc \
src/thrift/generate/t_dart_generator.cc \
src/thrift/generate/t_delphi_generator.cc \
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index dc9793f..cbcf8ea 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -57,6 +57,7 @@
<ClCompile Include="src\thrift\generate\t_c_glib_generator.cc" />
<ClCompile Include="src\thrift\generate\t_cl_generator.cc" />
<ClCompile Include="src\thrift\generate\t_cpp_generator.cc" />
+ <ClCompile Include="src\thrift\generate\t_csharp_generator.cc" />
<ClCompile Include="src\thrift\generate\t_d_generator.cc" />
<ClCompile Include="src\thrift\generate\t_dart_generator.cc" />
<ClCompile Include="src\thrift\generate\t_delphi_generator.cc" />
diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters
index 360c446..fcb3230 100644
--- a/compiler/cpp/compiler.vcxproj.filters
+++ b/compiler/cpp/compiler.vcxproj.filters
@@ -101,6 +101,9 @@
<ClCompile Include="src\generate\t_cpp_generator.cc">
<Filter>generate</Filter>
</ClCompile>
+ <ClCompile Include="src\generate\t_csharp_generator.cc">
+ <Filter>generate</Filter>
+ </ClCompile>
<ClCompile Include="src\generate\t_c_glib_generator.cc">
<Filter>generate</Filter>
</ClCompile>
diff --git a/compiler/cpp/src/thrift/generate/t_csharp_generator.cc b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
new file mode 100644
index 0000000..e4d99b2
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
@@ -0,0 +1,3259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+struct member_mapping_scope {
+ void* scope_member;
+ std::map<std::string, std::string> mapping_table;
+};
+
+class t_csharp_generator : public t_oop_generator {
+public:
+ t_csharp_generator(t_program* program,
+ const std::map<std::string, std::string>& parsed_options,
+ const std::string& option_string)
+ : t_oop_generator(program) {
+ (void)option_string;
+
+ std::map<std::string, std::string>::const_iterator iter;
+
+ async_ = false;
+ nullable_ = false;
+ hashcode_ = false;
+ union_ = false;
+ serialize_ = false;
+ wcf_ = false;
+ wcf_namespace_.clear();
+ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+ if( iter->first.compare("async") == 0) {
+ async_ = true;
+ } else if( iter->first.compare("nullable") == 0) {
+ nullable_ = true;
+ } else if( iter->first.compare("hashcode") == 0) {
+ hashcode_ = true;
+ } else if( iter->first.compare("union") == 0) {
+ union_ = true;
+ } else if( iter->first.compare("serial") == 0) {
+ serialize_ = true;
+ wcf_namespace_ = iter->second; // since there can be only one namespace
+ } else if( iter->first.compare("wcf") == 0) {
+ wcf_ = true;
+ wcf_namespace_ = iter->second;
+ } else {
+ throw "unknown option csharp:" + iter->first;
+ }
+ }
+
+ out_dir_base_ = "gen-csharp";
+ }
+ void init_generator() override;
+ void close_generator() override;
+
+ void generate_consts(std::vector<t_const*> consts) override;
+
+ void generate_typedef(t_typedef* ttypedef) override;
+ void generate_enum(t_enum* tenum) override;
+ void generate_struct(t_struct* tstruct) override;
+ void generate_union(t_struct* tunion);
+ void generate_xception(t_struct* txception) override;
+ void generate_service(t_service* tservice) override;
+ void generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset);
+ void generate_csharp_property(ostream& out,
+ t_field* tfield,
+ bool isPublic,
+ bool includeIsset = true,
+ std::string fieldPrefix = "");
+ bool print_const_value(std::ostream& 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::ostream& out,
+ std::string name,
+ t_type* type,
+ t_const_value* value);
+ void print_const_constructor(std::ostream& out, std::vector<t_const*> consts);
+ void print_const_def_value(std::ostream& out,
+ std::string name,
+ t_type* type,
+ t_const_value* value);
+
+ void generate_csharp_struct(t_struct* tstruct, bool is_exception);
+ void generate_csharp_union(t_struct* tunion);
+ void generate_csharp_struct_definition(std::ostream& out,
+ t_struct* tstruct,
+ bool is_xception = false,
+ bool in_class = false,
+ bool is_result = false);
+ void generate_csharp_union_definition(std::ostream& out, t_struct* tunion);
+ void generate_csharp_union_class(std::ostream& out, t_struct* tunion, t_field* tfield);
+ void generate_csharp_wcffault(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_reader(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_result_writer(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_writer(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_tostring(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_equals(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_struct_hashcode(std::ostream& out, t_struct* tstruct);
+ void generate_csharp_union_reader(std::ostream& out, t_struct* tunion);
+
+ void generate_function_helpers(t_function* tfunction);
+ void generate_service_interface(t_service* tservice);
+ void generate_separate_service_interfaces(t_service* tservice);
+ void generate_sync_service_interface(t_service* tservice);
+ void generate_async_service_interface(t_service* tservice);
+ void generate_combined_service_interface(t_service* tservice);
+ void generate_silverlight_async_methods(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_service_server_sync(t_service* tservice);
+ void generate_service_server_async(t_service* tservice);
+ void generate_process_function(t_service* tservice, t_function* function);
+ void generate_process_function_async(t_service* tservice, t_function* function);
+
+ void generate_deserialize_field(std::ostream& out,
+ t_field* tfield,
+ std::string prefix = "",
+ bool is_propertyless = false);
+ void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+ void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+ void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+ void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+ void generate_deserialize_list_element(std::ostream& out, t_list* list, std::string prefix = "");
+ void generate_serialize_field(std::ostream& out,
+ t_field* tfield,
+ std::string prefix = "",
+ bool is_element = false,
+ bool is_propertyless = false);
+ void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+ void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+ void generate_serialize_map_element(std::ostream& out,
+ t_map* tmap,
+ std::string iter,
+ std::string map);
+ void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+ void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+ void generate_csharp_doc(std::ostream& out, t_field* field);
+ void generate_csharp_doc(std::ostream& out, t_doc* tdoc);
+ void generate_csharp_doc(std::ostream& out, t_function* tdoc);
+ void generate_csharp_docstring_comment(std::ostream& out, string contents);
+
+ void start_csharp_namespace(std::ostream& out);
+ void end_csharp_namespace(std::ostream& 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,
+ bool in_param = false,
+ bool is_required = false);
+ std::string base_type_name(t_base_type* tbase,
+ bool in_container = false,
+ bool in_param = false,
+ bool is_required = false);
+ std::string declare_field(t_field* tfield, bool init = false, std::string prefix = "");
+ std::string function_signature_async_begin(t_function* tfunction, std::string prefix = "");
+ std::string function_signature_async_end(t_function* tfunction, std::string prefix = "");
+ std::string function_signature_async(t_function* tfunction, std::string prefix = "");
+ 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);
+ std::string prop_name(t_field* tfield, bool suppress_mapping = false);
+ std::string get_enum_class_name(t_type* type) override;
+
+ bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; }
+
+ bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; }
+
+ 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_;
+ ofstream_with_content_based_conditional_update f_service_;
+ std::string namespace_dir_;
+ bool async_;
+ bool nullable_;
+ bool union_;
+ bool hashcode_;
+ bool serialize_;
+ bool wcf_;
+ std::string wcf_namespace_;
+
+ std::map<std::string, int> csharp_keywords;
+ std::vector<member_mapping_scope> member_mapping_scopes;
+
+ void init_keywords();
+ std::string normalize_name(std::string name);
+ std::string make_valid_csharp_identifier(std::string const& fromName);
+ void prepare_member_name_mapping(t_struct* tstruct);
+ void prepare_member_name_mapping(void* scope,
+ const vector<t_field*>& members,
+ const string& structname);
+ void cleanup_member_name_mapping(void* scope);
+ string get_mapped_member_name(string oldname);
+};
+
+void t_csharp_generator::init_generator() {
+ MKDIR(get_out_dir().c_str());
+ namespace_name_ = program_->get_namespace("csharp");
+
+ 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;
+ init_keywords();
+
+ while( ! member_mapping_scopes.empty()) {
+ cleanup_member_name_mapping( member_mapping_scopes.back().scope_member);
+ }
+
+ pverbose("C# options:\n");
+ pverbose("- async ...... %s\n", (async_ ? "ON" : "off"));
+ pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off"));
+ pverbose("- union ...... %s\n", (union_ ? "ON" : "off"));
+ pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off"));
+ pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off"));
+ pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off"));
+}
+
+std::string t_csharp_generator::normalize_name(std::string name) {
+ string tmp(name);
+ std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
+
+ // un-conflict keywords by prefixing with "@"
+ if (csharp_keywords.find(tmp) != csharp_keywords.end()) {
+ return "@" + name;
+ }
+
+ // no changes necessary
+ return name;
+}
+
+void t_csharp_generator::init_keywords() {
+ csharp_keywords.clear();
+
+ // C# keywords
+ csharp_keywords["abstract"] = 1;
+ csharp_keywords["as"] = 1;
+ csharp_keywords["base"] = 1;
+ csharp_keywords["bool"] = 1;
+ csharp_keywords["break"] = 1;
+ csharp_keywords["byte"] = 1;
+ csharp_keywords["case"] = 1;
+ csharp_keywords["catch"] = 1;
+ csharp_keywords["char"] = 1;
+ csharp_keywords["checked"] = 1;
+ csharp_keywords["class"] = 1;
+ csharp_keywords["const"] = 1;
+ csharp_keywords["continue"] = 1;
+ csharp_keywords["decimal"] = 1;
+ csharp_keywords["default"] = 1;
+ csharp_keywords["delegate"] = 1;
+ csharp_keywords["do"] = 1;
+ csharp_keywords["double"] = 1;
+ csharp_keywords["else"] = 1;
+ csharp_keywords["enum"] = 1;
+ csharp_keywords["event"] = 1;
+ csharp_keywords["explicit"] = 1;
+ csharp_keywords["extern"] = 1;
+ csharp_keywords["false"] = 1;
+ csharp_keywords["finally"] = 1;
+ csharp_keywords["fixed"] = 1;
+ csharp_keywords["float"] = 1;
+ csharp_keywords["for"] = 1;
+ csharp_keywords["foreach"] = 1;
+ csharp_keywords["goto"] = 1;
+ csharp_keywords["if"] = 1;
+ csharp_keywords["implicit"] = 1;
+ csharp_keywords["in"] = 1;
+ csharp_keywords["int"] = 1;
+ csharp_keywords["interface"] = 1;
+ csharp_keywords["internal"] = 1;
+ csharp_keywords["is"] = 1;
+ csharp_keywords["lock"] = 1;
+ csharp_keywords["long"] = 1;
+ csharp_keywords["namespace"] = 1;
+ csharp_keywords["new"] = 1;
+ csharp_keywords["null"] = 1;
+ csharp_keywords["object"] = 1;
+ csharp_keywords["operator"] = 1;
+ csharp_keywords["out"] = 1;
+ csharp_keywords["override"] = 1;
+ csharp_keywords["params"] = 1;
+ csharp_keywords["private"] = 1;
+ csharp_keywords["protected"] = 1;
+ csharp_keywords["public"] = 1;
+ csharp_keywords["readonly"] = 1;
+ csharp_keywords["ref"] = 1;
+ csharp_keywords["return"] = 1;
+ csharp_keywords["sbyte"] = 1;
+ csharp_keywords["sealed"] = 1;
+ csharp_keywords["short"] = 1;
+ csharp_keywords["sizeof"] = 1;
+ csharp_keywords["stackalloc"] = 1;
+ csharp_keywords["static"] = 1;
+ csharp_keywords["string"] = 1;
+ csharp_keywords["struct"] = 1;
+ csharp_keywords["switch"] = 1;
+ csharp_keywords["this"] = 1;
+ csharp_keywords["throw"] = 1;
+ csharp_keywords["true"] = 1;
+ csharp_keywords["try"] = 1;
+ csharp_keywords["typeof"] = 1;
+ csharp_keywords["uint"] = 1;
+ csharp_keywords["ulong"] = 1;
+ csharp_keywords["unchecked"] = 1;
+ csharp_keywords["unsafe"] = 1;
+ csharp_keywords["ushort"] = 1;
+ csharp_keywords["using"] = 1;
+ csharp_keywords["virtual"] = 1;
+ csharp_keywords["void"] = 1;
+ csharp_keywords["volatile"] = 1;
+ csharp_keywords["while"] = 1;
+
+ // C# contextual keywords
+ csharp_keywords["add"] = 1;
+ csharp_keywords["alias"] = 1;
+ csharp_keywords["ascending"] = 1;
+ csharp_keywords["async"] = 1;
+ csharp_keywords["await"] = 1;
+ csharp_keywords["descending"] = 1;
+ csharp_keywords["dynamic"] = 1;
+ csharp_keywords["from"] = 1;
+ csharp_keywords["get"] = 1;
+ csharp_keywords["global"] = 1;
+ csharp_keywords["group"] = 1;
+ csharp_keywords["into"] = 1;
+ csharp_keywords["join"] = 1;
+ csharp_keywords["let"] = 1;
+ csharp_keywords["orderby"] = 1;
+ csharp_keywords["partial"] = 1;
+ csharp_keywords["remove"] = 1;
+ csharp_keywords["select"] = 1;
+ csharp_keywords["set"] = 1;
+ csharp_keywords["value"] = 1;
+ csharp_keywords["var"] = 1;
+ csharp_keywords["where"] = 1;
+ csharp_keywords["yield"] = 1;
+}
+
+void t_csharp_generator::start_csharp_namespace(ostream& out) {
+ if (!namespace_name_.empty()) {
+ out << "namespace " << namespace_name_ << "\n";
+ scope_up(out);
+ }
+}
+
+void t_csharp_generator::end_csharp_namespace(ostream& 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 System.IO;\n"
+ + ((async_) ? "using System.Threading.Tasks;\n" : "") + "using Thrift;\n"
+ + "using Thrift.Collections;\n" + ((serialize_ || wcf_) ? "#if !SILVERLIGHT\n" : "")
+ + ((serialize_ || wcf_) ? "using System.Xml.Serialization;\n" : "")
+ + ((serialize_ || wcf_) ? "#endif\n" : "")
+ + "using System.Runtime.Serialization;\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)ttypedef;
+}
+
+void t_csharp_generator::generate_enum(t_enum* tenum) {
+ string f_enum_name = namespace_dir_ + "/" + (tenum->get_name()) + ".cs";
+ ofstream_with_content_based_conditional_update f_enum;
+ f_enum.open(f_enum_name.c_str());
+
+ f_enum << autogen_comment() << endl;
+
+ start_csharp_namespace(f_enum);
+
+ generate_csharp_doc(f_enum, tenum);
+
+ 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;
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ generate_csharp_doc(f_enum, *c_iter);
+
+ int value = (*c_iter)->get_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_ + '/' + program_name_ + ".Constants.cs";
+ ofstream_with_content_based_conditional_update 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 static class " << make_valid_csharp_identifier(program_name_)
+ << "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) {
+ generate_csharp_doc(f_consts, (*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::ostream& 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*, t_const_value::value_compare>& val = value->get_map();
+ map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+ prepare_member_name_mapping((t_struct*)type);
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ t_field* field = NULL;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+ field = (*f_iter);
+ }
+ }
+ if (field == NULL) {
+ throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+ }
+ t_type* field_type = field->get_type();
+ string val = render_const_value(out, name, field_type, v_iter->second);
+ indent(out) << name << "." << prop_name(field) << " = " << val << ";" << endl;
+ }
+ cleanup_member_name_mapping((t_struct*)type);
+ } 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*, t_const_value::value_compare>& val = value->get_map();
+ map<t_const_value*, t_const_value*, t_const_value::value_compare>::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::ostream& out, std::vector<t_const*> consts) {
+ indent(out) << "static " << make_valid_csharp_identifier(program_name_).c_str() << "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::ostream& 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;
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ if (!defval || needtype) {
+ out << (in_static ? "" : type->is_base_type() ? "public const " : "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_identifier_name()
+ << ";" << 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(ostream& out,
+ string name,
+ t_type* type,
+ t_const_value* value) {
+ (void)name;
+ 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 << '"' << get_escaped_string(value) << '"';
+ break;
+ case t_base_type::TYPE_BOOL:
+ render << ((value->get_integer() > 0) ? "true" : "false");
+ break;
+ case t_base_type::TYPE_I8:
+ 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 " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ render << type->get_name() << "." << value->get_identifier_name();
+ } 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) {
+ if (union_ && tstruct->is_union()) {
+ generate_csharp_union(tstruct);
+ } else {
+ 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_with_content_based_conditional_update f_struct;
+
+ f_struct.open(f_struct_name.c_str());
+
+ f_struct << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+ generate_csharp_struct_definition(f_struct, tstruct, is_exception);
+
+ f_struct.close();
+}
+
+void t_csharp_generator::generate_csharp_struct_definition(ostream& out,
+ t_struct* tstruct,
+ bool is_exception,
+ bool in_class,
+ bool is_result) {
+
+ if (!in_class) {
+ start_csharp_namespace(out);
+ }
+
+ out << endl;
+
+ generate_csharp_doc(out, tstruct);
+ prepare_member_name_mapping(tstruct);
+
+ indent(out) << "#if !SILVERLIGHT" << endl;
+ indent(out) << "[Serializable]" << endl;
+ indent(out) << "#endif" << endl;
+ if ((serialize_ || wcf_) && !is_exception) {
+ indent(out) << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]"
+ << endl; // do not make exception classes directly WCF serializable, we provide a
+ // separate "fault" for that
+ }
+ bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+ indent(out) << "public " << (is_final ? "sealed " : "") << "partial class "
+ << normalize_name(tstruct->get_name()) << " : ";
+
+ if (is_exception) {
+ out << "TException, ";
+ }
+ out << "TBase";
+
+ out << endl;
+
+ scope_up(out);
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ // make private members with public Properties
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ // if the field is requied, then we use auto-properties
+ if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+ indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+ }
+ }
+ out << endl;
+
+ bool has_non_required_fields = false;
+ bool has_non_required_default_value_fields = false;
+ bool has_required_fields = false;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ generate_csharp_doc(out, *m_iter);
+ generate_property(out, *m_iter, true, true);
+ bool is_required = field_is_required((*m_iter));
+ bool has_default = field_has_default((*m_iter));
+ if (is_required) {
+ has_required_fields = true;
+ } else {
+ if (has_default) {
+ has_non_required_default_value_fields = true;
+ }
+ has_non_required_fields = true;
+ }
+ }
+
+ bool generate_isset = (nullable_ && has_non_required_default_value_fields)
+ || (!nullable_ && has_non_required_fields);
+ if (generate_isset) {
+ out << endl;
+ if (serialize_ || wcf_) {
+ out << indent() << "[XmlIgnore] // XmlSerializer" << endl << indent()
+ << "[DataMember(Order = 1)] // XmlObjectSerializer, DataContractJsonSerializer, etc."
+ << endl;
+ }
+ out << indent() << "public Isset __isset;" << endl << indent() << "#if !SILVERLIGHT" << endl
+ << indent() << "[Serializable]" << endl << indent() << "#endif" << endl;
+ if (serialize_ || wcf_) {
+ indent(out) << "[DataContract]" << endl;
+ }
+ indent(out) << "public struct Isset {" << endl;
+ indent_up();
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ bool is_required = field_is_required((*m_iter));
+ bool has_default = field_has_default((*m_iter));
+ // if it is required, don't need Isset for that variable
+ // if it is not required, if it has a default value, we need to generate Isset
+ // if we are not nullable, then we generate Isset
+ if (!is_required && (!nullable_ || has_default)) {
+ if (serialize_ || wcf_) {
+ indent(out) << "[DataMember]" << endl;
+ }
+ indent(out) << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl;
+ }
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ if (generate_isset && (serialize_ || wcf_)) {
+ indent(out) << "#region XmlSerializer support" << endl << endl;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ bool is_required = field_is_required((*m_iter));
+ bool has_default = field_has_default((*m_iter));
+ // if it is required, don't need Isset for that variable
+ // if it is not required, if it has a default value, we need to generate Isset
+ // if we are not nullable, then we generate Isset
+ if (!is_required && (!nullable_ || has_default)) {
+ indent(out) << "public bool ShouldSerialize" << prop_name((*m_iter)) << "()" << endl;
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl;
+ indent_down();
+ indent(out) << "}" << endl << endl;
+ }
+ }
+
+ indent(out) << "#endregion XmlSerializer support" << endl << endl;
+ }
+ }
+
+ // We always want a default, no argument constructor for Reading
+ indent(out) << "public " << normalize_name(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) {
+ if (field_is_required((*m_iter))) {
+ print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
+ } else {
+ print_const_value(out,
+ "this._" + (*m_iter)->get_name(),
+ t,
+ (*m_iter)->get_value(),
+ true,
+ true);
+ // Optionals with defaults are marked set
+ indent(out) << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;"
+ << endl;
+ }
+ }
+ }
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ if (has_required_fields) {
+ indent(out) << "public " << tstruct->get_name() << "(";
+ bool first = true;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (field_is_required((*m_iter))) {
+ if (first) {
+ first = false;
+ } else {
+ out << ", ";
+ }
+ out << type_name((*m_iter)->get_type()) << " " << normalize_name((*m_iter)->get_name());
+ }
+ }
+ out << ") : this() {" << endl;
+ indent_up();
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (field_is_required((*m_iter))) {
+ indent(out) << "this." << prop_name((*m_iter)) << " = " << normalize_name((*m_iter)->get_name()) << ";"
+ << endl;
+ }
+ }
+
+ 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);
+ }
+ if (hashcode_) {
+ generate_csharp_struct_equals(out, tstruct);
+ generate_csharp_struct_hashcode(out, tstruct);
+ }
+ generate_csharp_struct_tostring(out, tstruct);
+ scope_down(out);
+ out << endl;
+
+ // generate a corresponding WCF fault to wrap the exception
+ if ((serialize_ || wcf_) && is_exception) {
+ generate_csharp_wcffault(out, tstruct);
+ }
+
+ cleanup_member_name_mapping(tstruct);
+ if (!in_class) {
+ end_csharp_namespace(out);
+ }
+}
+
+void t_csharp_generator::generate_csharp_wcffault(ostream& out, t_struct* tstruct) {
+ out << endl;
+ indent(out) << "#if !SILVERLIGHT" << endl;
+ indent(out) << "[Serializable]" << endl;
+ indent(out) << "#endif" << endl;
+ indent(out) << "[DataContract]" << endl;
+ bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+ indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name()
+ << "Fault" << endl;
+
+ scope_up(out);
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ // make private members with public Properties
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ // if the field is requied, then we use auto-properties
+ if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+ indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+ }
+ }
+ out << endl;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ generate_property(out, *m_iter, true, false);
+ }
+
+ scope_down(out);
+ out << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_reader(ostream& out, t_struct* tstruct) {
+ indent(out) << "public void Read (TProtocol iprot)" << endl;
+ scope_up(out);
+
+ out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+ out << indent() << "try" << endl;
+ scope_up(out);
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // Required variables aren't in __isset, so we need tmp vars to check them
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (field_is_required((*f_iter))) {
+ indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+ }
+ }
+
+ indent(out) << "TField field;" << endl << indent() << "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) {
+ bool is_required = field_is_required((*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);
+ if (is_required) {
+ indent(out) << "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;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (field_is_required((*f_iter))) {
+ indent(out) << "if (!isset_" << (*f_iter)->get_name() << ")" << endl;
+ indent_up();
+ out << indent()
+ << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+ << "\"required field " << prop_name((*f_iter)) << " not set\");"
+ << endl;
+ indent_down();
+ }
+ }
+
+ scope_down(out);
+ out << indent() << "finally" << endl;
+ scope_up(out);
+ out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+ scope_down(out);
+
+ indent_down();
+
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_writer(ostream& out, t_struct* tstruct) {
+ out << indent() << "public void Write(TProtocol oprot) {" << endl;
+ indent_up();
+
+ out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+ out << indent() << "try" << endl;
+ scope_up(out);
+
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+ indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+ if (fields.size() > 0) {
+ indent(out) << "TField field = new TField();" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ bool is_required = field_is_required((*f_iter));
+ bool has_default = field_has_default((*f_iter));
+ bool null_allowed = type_can_be_null((*f_iter)->get_type());
+
+ if (is_required)
+ {
+ if (null_allowed) {
+ indent(out) << "if (" << prop_name((*f_iter)) << " == null)" << endl;
+ indent_up();
+ out << indent()
+ << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+ << "\"required field " << prop_name((*f_iter)) << " not set\");"
+ << endl;
+ indent_down();
+ }
+ }
+ else
+ {
+ if (nullable_ && !has_default) {
+ indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+ }
+ else if (null_allowed) {
+ out << indent()
+ << "if (" << prop_name((*f_iter)) << " != null && __isset."
+ << normalize_name((*f_iter)->get_name()) << ") {"
+ << endl;
+ }
+ else {
+ indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << 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);
+
+ indent(out) << "oprot.WriteFieldEnd();" << endl;
+ if (!is_required) {
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ }
+ }
+
+ indent(out) << "oprot.WriteFieldStop();" << endl;
+ indent(out) << "oprot.WriteStructEnd();" << endl;
+
+ scope_down(out);
+ out << indent() << "finally" << endl;
+ scope_up(out);
+ out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+ scope_down(out);
+
+ indent_down();
+
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_result_writer(ostream& out, t_struct* tstruct) {
+ indent(out) << "public void Write(TProtocol oprot) {" << endl;
+ indent_up();
+
+ out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+ out << indent() << "try" << endl;
+ scope_up(out);
+
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+ indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+ if (fields.size() > 0) {
+ indent(out) << "TField field = new TField();" << 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 ";
+ }
+
+ if (nullable_) {
+ out << "(this." << prop_name((*f_iter)) << " != null) {" << endl;
+ } else {
+ out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+ }
+ indent_up();
+
+ bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type());
+ if (null_allowed) {
+ indent(out) << "if (" << prop_name(*f_iter) << " != null) {" << endl;
+ indent_up();
+ }
+
+ indent(out) << "field.Name = \"" << prop_name(*f_iter) << "\";" << 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);
+
+ 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;
+
+ scope_down(out);
+ out << indent() << "finally" << endl;
+ scope_up(out);
+ out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+ scope_down(out);
+
+ indent_down();
+
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_tostring(ostream& 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 useFirstFlag = false;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (!field_is_required((*f_iter))) {
+ indent(out) << "bool __first = true;" << endl;
+ useFirstFlag = true;
+ }
+ break;
+ }
+
+ bool had_required = false; // set to true after first required field has been processed
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ bool is_required = field_is_required((*f_iter));
+ bool has_default = field_has_default((*f_iter));
+ if (nullable_ && !has_default && !is_required) {
+ indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+ indent_up();
+ } else if (!is_required) {
+ bool null_allowed = type_can_be_null((*f_iter)->get_type());
+ if (null_allowed) {
+ indent(out) << "if (" << prop_name((*f_iter)) << " != null && __isset."
+ << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+ indent_up();
+ } else {
+ indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+ indent_up();
+ }
+ }
+
+ if (useFirstFlag && (!had_required)) {
+ indent(out) << "if(!__first) { __sb.Append(\", \"); }" << endl;
+ if (!is_required) {
+ indent(out) << "__first = false;" << endl;
+ }
+ indent(out) << "__sb.Append(\"" << prop_name((*f_iter)) << ": \");" << endl;
+ } else {
+ indent(out) << "__sb.Append(\", " << prop_name((*f_iter)) << ": \");" << endl;
+ }
+
+ t_type* ttype = (*f_iter)->get_type();
+ if (ttype->is_xception() || ttype->is_struct()) {
+ indent(out) << "__sb.Append(" << prop_name((*f_iter))
+ << "== null ? \"<null>\" : " << prop_name((*f_iter)) << ".ToString());" << endl;
+ } else {
+ indent(out) << "__sb.Append(" << prop_name((*f_iter)) << ");" << endl;
+ }
+
+ if (!is_required) {
+ indent_down();
+ indent(out) << "}" << endl;
+ } else {
+ had_required = true; // now __first must be false, so we don't need to check it anymore
+ }
+ }
+
+ indent(out) << "__sb.Append(\")\");" << endl;
+ indent(out) << "return __sb.ToString();" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_union(t_struct* tunion) {
+ string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
+ ofstream_with_content_based_conditional_update f_union;
+
+ f_union.open(f_union_name.c_str());
+
+ f_union << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+ generate_csharp_union_definition(f_union, tunion);
+
+ f_union.close();
+}
+
+void t_csharp_generator::generate_csharp_union_definition(std::ostream& out, t_struct* tunion) {
+ // Let's define the class first
+ start_csharp_namespace(out);
+
+ indent(out) << "public abstract partial class " << tunion->get_name() << " : TAbstractBase {"
+ << endl;
+
+ indent_up();
+
+ indent(out) << "public abstract void Write(TProtocol protocol);" << endl;
+ indent(out) << "public readonly int Isset;" << endl;
+ indent(out) << "public abstract object Data { get; }" << endl;
+
+ indent(out) << "protected " << tunion->get_name() << "(int isset) {" << endl;
+ indent_up();
+ indent(out) << "Isset = isset;" << endl;
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ indent(out) << "public class ___undefined : " << tunion->get_name() << " {" << endl;
+ indent_up();
+
+ indent(out) << "public override object Data { get { return null; } }" << endl;
+
+ indent(out) << "public ___undefined() : base(0) {}" << endl << endl;
+
+ indent(out) << "public override void Write(TProtocol protocol) {" << endl;
+ indent_up();
+ indent(out) << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist "
+ "an union type which is not set.\");" << endl;
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ const vector<t_field*>& fields = tunion->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ generate_csharp_union_class(out, tunion, (*f_iter));
+ }
+
+ generate_csharp_union_reader(out, tunion);
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ end_csharp_namespace(out);
+}
+
+void t_csharp_generator::generate_csharp_union_class(std::ostream& out,
+ t_struct* tunion,
+ t_field* tfield) {
+ indent(out) << "public " << type_name(tfield->get_type()) << " As_" << tfield->get_name() << endl;
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "get" << endl;
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "return (" << tfield->get_key() << " == Isset) ? (" << type_name(tfield->get_type()) << ")Data : default(" << type_name(tfield->get_type()) << ");" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ indent_down();
+ indent(out) << "}" << endl
+ << endl;
+
+
+ indent(out) << "public class " << tfield->get_name() << " : " << tunion->get_name() << " {"
+ << endl;
+ indent_up();
+ indent(out) << "private " << type_name(tfield->get_type()) << " _data;" << endl;
+ indent(out) << "public override object Data { get { return _data; } }" << endl;
+ indent(out) << "public " << tfield->get_name() << "(" << type_name(tfield->get_type())
+ << " data) : base("<< tfield->get_key() <<") {" << endl;
+ indent_up();
+ indent(out) << "this._data = data;" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ indent(out) << "public override void Write(TProtocol oprot) {" << endl;
+ indent_up();
+
+ out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+ out << indent() << "try" << endl;
+ scope_up(out);
+
+ indent(out) << "TStruct struc = new TStruct(\"" << tunion->get_name() << "\");" << endl;
+ indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+ indent(out) << "TField field = new TField();" << endl;
+ indent(out) << "field.Name = \"" << tfield->get_name() << "\";" << endl;
+ indent(out) << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl;
+ indent(out) << "field.ID = " << tfield->get_key() << ";" << endl;
+ indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+ generate_serialize_field(out, tfield, "_data", true, true);
+
+ indent(out) << "oprot.WriteFieldEnd();" << endl;
+ indent(out) << "oprot.WriteFieldStop();" << endl;
+ indent(out) << "oprot.WriteStructEnd();" << endl;
+ indent_down();
+
+ scope_down(out);
+ out << indent() << "finally" << endl;
+ scope_up(out);
+ out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+ scope_down(out);
+
+ indent(out) << "}" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_equals(ostream& out, t_struct* tstruct) {
+ indent(out) << "public override bool Equals(object that) {" << endl;
+ indent_up();
+
+ indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl;
+ indent(out) << "if (other == null) return false;" << endl;
+ indent(out) << "if (ReferenceEquals(this, other)) return true;" << 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) << "return ";
+ indent_up();
+ } else {
+ out << endl;
+ indent(out) << "&& ";
+ }
+ if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+ out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset."
+ << normalize_name((*f_iter)->get_name()) << ") && ((!__isset."
+ << normalize_name((*f_iter)->get_name()) << ") || (";
+ }
+ t_type* ttype = (*f_iter)->get_type();
+ if (ttype->is_container() || ttype->is_binary()) {
+ out << "TCollections.Equals(";
+ } else {
+ out << "System.Object.Equals(";
+ }
+ out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
+ if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+ out << ")))";
+ }
+ }
+ if (first) {
+ indent(out) << "return true;" << endl;
+ } else {
+ out << ";" << endl;
+ indent_down();
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_hashcode(ostream& out, t_struct* tstruct) {
+ indent(out) << "public override int GetHashCode() {" << endl;
+ indent_up();
+
+ indent(out) << "int hashcode = 0;" << endl;
+ indent(out) << "unchecked {" << endl;
+ indent_up();
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_type* ttype = (*f_iter)->get_type();
+ indent(out) << "hashcode = (hashcode * 397) ^ ";
+ if (field_is_required((*f_iter))) {
+ out << "(";
+ } else if (nullable_) {
+ out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
+ } else {
+ out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : ";
+ }
+ if (ttype->is_container()) {
+ out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))";
+ } else {
+ out << "(" << prop_name((*f_iter)) << ".GetHashCode())";
+ }
+ out << ");" << endl;
+ }
+
+ indent_down();
+ indent(out) << "}" << endl;
+ indent(out) << "return hashcode;" << 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() << endl;
+
+ start_csharp_namespace(f_service_);
+
+ indent(f_service_) << "public partial class " << normalize_name(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) {
+ generate_separate_service_interfaces(tservice);
+}
+
+void t_csharp_generator::generate_separate_service_interfaces(t_service* tservice) {
+ generate_sync_service_interface(tservice);
+
+ if (async_) {
+ generate_async_service_interface(tservice);
+ }
+
+ generate_combined_service_interface(tservice);
+}
+
+void t_csharp_generator::generate_sync_service_interface(t_service* tservice) {
+ string extends = "";
+ string extends_iface = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_iface = " : " + extends + ".ISync";
+ }
+
+ generate_csharp_doc(f_service_, tservice);
+
+ if (wcf_) {
+ indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+ }
+ indent(f_service_) << "public interface ISync" << 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) {
+ generate_csharp_doc(f_service_, *f_iter);
+
+ // if we're using WCF, add the corresponding attributes
+ if (wcf_) {
+ indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+ const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+ + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+ }
+ }
+
+ indent(f_service_) << function_signature(*f_iter) << ";" << endl;
+ }
+ indent_down();
+ f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_async_service_interface(t_service* tservice) {
+ string extends = "";
+ string extends_iface = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_iface = " : " + extends + ".IAsync";
+ }
+
+ generate_csharp_doc(f_service_, tservice);
+
+ if (wcf_) {
+ indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+ }
+ indent(f_service_) << "public interface IAsync" << 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) {
+ generate_csharp_doc(f_service_, *f_iter);
+
+ // if we're using WCF, add the corresponding attributes
+ if (wcf_) {
+ indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+ const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+ + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+ }
+ }
+
+ indent(f_service_) << function_signature_async(*f_iter) << ";" << endl;
+ }
+ indent_down();
+ f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_combined_service_interface(t_service* tservice) {
+ string extends_iface = " : ISync";
+
+ if (async_) {
+ extends_iface += ", IAsync";
+ }
+
+ generate_csharp_doc(f_service_, tservice);
+
+ if (wcf_) {
+ indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+ }
+
+ indent(f_service_) << "public interface Iface" << extends_iface << " {" << endl;
+
+ indent_up();
+
+ // We need to generate extra old style async methods for silverlight. Since
+ // this isn't something you'd want to implement server-side, just put them into
+ // the main Iface interface.
+ generate_silverlight_async_methods(tservice);
+
+ indent_down();
+
+ f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_silverlight_async_methods(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) {
+ generate_csharp_doc(f_service_, *f_iter);
+
+ // For backwards compatibility, include the Begin_, End_ methods if we're generating
+ // with the async flag. I'm not sure this is necessary, so someone with more knowledge
+ // can maybe remove these checks if they know it's safe.
+ if (!async_) {
+ indent(f_service_) << "#if SILVERLIGHT" << endl;
+ }
+
+ indent(f_service_) << function_signature_async_begin(*f_iter, "Begin_") << ";" << endl;
+ indent(f_service_) << function_signature_async_end(*f_iter, "End_") << ";" << endl;
+
+ if (!async_) {
+ indent(f_service_) << "#endif" << 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, ";
+ } else {
+ extends_client = "IDisposable, ";
+ }
+
+ generate_csharp_doc(f_service_, tservice);
+
+ 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)";
+ if (!extends.empty()) {
+ f_service_ << " : base(iprot, oprot)";
+ }
+ f_service_ << endl;
+
+ scope_up(f_service_);
+ if (extends.empty()) {
+ f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl;
+ }
+ scope_down(f_service_);
+
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent()
+ << "protected TProtocol oprot_;" << endl << indent() << "protected int seqid_;"
+ << endl << endl;
+
+ f_service_ << indent() << "public TProtocol InputProtocol" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "get { return iprot_; }" << endl;
+ scope_down(f_service_);
+
+ f_service_ << indent() << "public TProtocol OutputProtocol" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "get { return oprot_; }" << endl;
+ scope_down(f_service_);
+ f_service_ << endl << endl;
+
+ indent(f_service_) << "#region \" IDisposable Support \"" << endl;
+ indent(f_service_) << "private bool _IsDisposed;" << endl << endl;
+ indent(f_service_) << "// IDisposable" << endl;
+ indent(f_service_) << "public void Dispose()" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "Dispose(true);" << endl;
+ scope_down(f_service_);
+ indent(f_service_) << endl << endl;
+ indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "if (!_IsDisposed)" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "if (disposing)" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "if (iprot_ != null)" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl;
+ scope_down(f_service_);
+ indent(f_service_) << "if (oprot_ != null)" << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl;
+ scope_down(f_service_);
+ scope_down(f_service_);
+ scope_down(f_service_);
+ indent(f_service_) << "_IsDisposed = true;" << endl;
+ scope_down(f_service_);
+ indent(f_service_) << "#endregion" << endl;
+ f_service_ << 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_) << endl;
+
+ if (!async_) {
+ indent(f_service_) << "#if SILVERLIGHT" << endl;
+ indent(f_service_) << endl;
+ }
+ // Begin_
+ indent(f_service_) << "public " << function_signature_async_begin(*f_iter, "Begin_") << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "return "
+ << "send_" << funname << "(callback, state";
+
+ t_struct* arg_struct = (*f_iter)->get_arglist();
+ prepare_member_name_mapping(arg_struct);
+
+ const vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator fld_iter;
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ f_service_ << ", ";
+ f_service_ << normalize_name((*fld_iter)->get_name());
+ }
+ f_service_ << ");" << endl;
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ // End
+ indent(f_service_) << "public " << function_signature_async_end(*f_iter, "End_") << endl;
+ scope_up(f_service_);
+ indent(f_service_) << "oprot_.Transport.EndFlush(asyncResult);" << endl;
+ if (!(*f_iter)->is_oneway()) {
+ 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;
+
+ // async
+ bool first;
+ if (async_) {
+ indent(f_service_) << "public async " << function_signature_async(*f_iter, "") << endl;
+ scope_up(f_service_);
+
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ indent(f_service_) << type_name((*f_iter)->get_returntype()) << " retval;" << endl;
+ indent(f_service_) << "retval = ";
+ } else {
+ indent(f_service_);
+ }
+ f_service_ << "await Task.Run(() =>" << endl;
+ scope_up(f_service_);
+ indent(f_service_);
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ f_service_ << "return ";
+ }
+ f_service_ << funname << "(";
+ 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;
+ indent_down();
+ indent(f_service_) << "});" << endl;
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ indent(f_service_) << "return retval;" << endl;
+ }
+ scope_down(f_service_);
+ f_service_ << endl;
+ }
+
+ if (!async_) {
+ indent(f_service_) << "#endif" << endl << endl;
+ }
+
+ generate_csharp_doc(f_service_, *f_iter);
+ indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+ scope_up(f_service_);
+
+ // silverlight invoke
+ if (!async_) {
+ indent(f_service_) << "#if SILVERLIGHT" << endl;
+
+ indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null";
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ f_service_ << ", " << normalize_name((*fld_iter)->get_name());
+ }
+ f_service_ << ");" << endl;
+
+ if (!(*f_iter)->is_oneway()) {
+ f_service_ << indent();
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ f_service_ << "return ";
+ }
+ f_service_ << "End_" << funname << "(asyncResult);" << endl;
+ }
+ f_service_ << endl;
+
+ indent(f_service_) << "#else" << endl;
+ }
+
+ // synchronous invoke
+ indent(f_service_) << "send_" << funname << "(";
+
+ first = true;
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << normalize_name((*fld_iter)->get_name());
+ }
+ f_service_ << ");" << endl;
+
+ if (!(*f_iter)->is_oneway()) {
+ f_service_ << indent();
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ f_service_ << "return ";
+ }
+ f_service_ << "recv_" << funname << "();" << endl;
+ }
+ f_service_ << endl;
+
+ if (!async_) {
+ indent(f_service_) << "#endif" << endl;
+ }
+ scope_down(f_service_);
+
+ // Send
+ t_function send_function(g_type_void,
+ string("send_") + (*f_iter)->get_name(),
+ (*f_iter)->get_arglist());
+
+ string argsname = (*f_iter)->get_name() + "_args";
+
+ if (!async_) {
+ indent(f_service_) << "#if SILVERLIGHT" << endl;
+ }
+
+ indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl;
+ scope_up(f_service_);
+
+ f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+ << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "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." << prop_name(*fld_iter) << " = "
+ << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+ }
+
+ f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+ << "oprot_.WriteMessageEnd();" << endl;
+ indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl;
+
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ if (!async_) {
+ indent(f_service_) << "#else" << endl;
+ f_service_ << endl;
+ }
+
+ indent(f_service_) << "public " << function_signature(&send_function) << endl;
+ scope_up(f_service_);
+
+ f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+ << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "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." << prop_name(*fld_iter) << " = "
+ << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+ }
+
+ f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+ << "oprot_.WriteMessageEnd();" << endl;
+
+ indent(f_service_) << "oprot_.Transport.Flush();" << endl;
+ cleanup_member_name_mapping(arg_struct);
+ scope_down(f_service_);
+
+ if (!async_) {
+ indent(f_service_) << "#endif" << endl;
+ }
+
+ f_service_ << endl;
+
+ if (!(*f_iter)->is_oneway()) {
+ 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_);
+
+ t_struct* xs = (*f_iter)->get_xceptions();
+ prepare_member_name_mapping(xs, xs->get_members(), resultname);
+
+ 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()) {
+ if (nullable_) {
+ if (type_can_be_null((*f_iter)->get_returntype())) {
+ f_service_ << indent() << "if (result.Success != null) {" << endl << indent()
+ << " return result.Success;" << endl << indent() << "}" << endl;
+ } else {
+ f_service_ << indent() << "if (result.Success.HasValue) {" << endl << indent()
+ << " return result.Success.Value;" << endl << indent() << "}" << endl;
+ }
+ } else {
+ f_service_ << indent() << "if (result.__isset.success) {" << endl << indent()
+ << " return result.Success;" << endl << indent() << "}" << endl;
+ }
+ }
+
+ 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) {
+ if (nullable_) {
+ f_service_ << indent() << "if (result." << prop_name(*x_iter) << " != null) {" << endl
+ << indent() << " throw result." << prop_name(*x_iter) << ";" << endl
+ << indent() << "}" << endl;
+ } else {
+ f_service_ << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name())
+ << ") {" << endl << indent() << " throw result." << prop_name(*x_iter) << ";"
+ << 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;
+ }
+
+ cleanup_member_name_mapping((*f_iter)->get_xceptions());
+ scope_down(f_service_);
+ f_service_ << endl;
+ }
+ }
+
+ indent_down();
+ indent(f_service_) << "}" << endl;
+}
+
+void t_csharp_generator::generate_service_server(t_service* tservice) {
+ if (async_) {
+ generate_service_server_async(tservice);
+ generate_service_server_sync(tservice);
+ }
+ else {
+ generate_service_server_sync(tservice);
+ }
+}
+
+void t_csharp_generator::generate_service_server_sync(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(ISync iface)";
+
+ if (!extends.empty()) {
+ f_service_ << " : base(iface)";
+ }
+ f_service_ << endl;
+ scope_up(f_service_);
+ 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()
+ << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl;
+ }
+
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ f_service_
+ << indent()
+ << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+ << endl;
+ }
+
+ f_service_ << indent() << "private ISync iface_;" << endl;
+
+ if (extends.empty()) {
+ f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+ "Dictionary<string, ProcessFunction>();" << endl;
+ }
+
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ indent(f_service_) << "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+ }
+ else {
+ indent(f_service_) << "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+ }
+ scope_up(f_service_);
+
+ f_service_ << indent() << "try" << endl;
+ scope_up(f_service_);
+
+ f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+ f_service_
+ << indent() << "ProcessFunction fn;" << endl << indent()
+ << "processMap_.TryGetValue(msg.Name, out fn);" << 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(msg.SeqID, iprot, oprot);" << endl;
+
+ scope_down(f_service_);
+
+ f_service_ << indent() << "catch (IOException)" << endl;
+ scope_up(f_service_);
+ f_service_ << indent() << "return false;" << endl;
+ scope_down(f_service_);
+
+ 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_service_server_async(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 + ".AsyncProcessor, ";
+ }
+
+ indent(f_service_) << "public class AsyncProcessor : " << extends_processor << "TAsyncProcessor {" << endl;
+ indent_up();
+
+ indent(f_service_) << "public AsyncProcessor(IAsync iface)";
+ if (!extends.empty()) {
+ f_service_ << " : base(iface)";
+ }
+ f_service_ << endl;
+ scope_up(f_service_);
+ 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()
+ << "\"] = " << (*f_iter)->get_name() << "_ProcessAsync;" << endl;
+ }
+
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ f_service_
+ << indent()
+ << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+ << endl;
+ }
+
+ f_service_ << indent() << "private IAsync iface_;" << endl;
+
+ if (extends.empty()) {
+ f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+ "Dictionary<string, ProcessFunction>();" << endl;
+ }
+
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ indent(f_service_) << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+ }
+ else {
+ indent(f_service_) << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+ }
+ scope_up(f_service_);
+
+ f_service_ << indent() << "try" << endl;
+ scope_up(f_service_);
+
+ f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+ f_service_
+ << indent() << "ProcessFunction fn;" << endl << indent()
+ << "processMap_.TryGetValue(msg.Name, out fn);" << 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() << "await fn(msg.SeqID, iprot, oprot);" << endl;
+
+ scope_down(f_service_);
+
+ f_service_ << indent() << "catch (IOException)" << endl;
+ scope_up(f_service_);
+ f_service_ << indent() << "return false;" << endl;
+ scope_down(f_service_);
+
+ 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_async(tservice, *f_iter);
+ }
+
+ indent_down();
+ indent(f_service_) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_function_helpers(t_function* tfunction) {
+ if (tfunction->is_oneway()) {
+ 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) {
+ (void)tservice;
+ indent(f_service_) << "public void " << tfunction->get_name()
+ << "_Process(int seqid, 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_oneway()) {
+ f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+ }
+
+ f_service_ << indent() << "try" << endl
+ << indent() << "{" << endl;
+ indent_up();
+
+ if (xceptions.size() > 0) {
+ f_service_ << indent() << "try" << endl
+ << indent() << "{" << 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_oneway() && !tfunction->get_returntype()->is_void()) {
+ f_service_ << "result.Success = ";
+ }
+ f_service_ << "iface_." << normalize_name(tfunction->get_name()) << "(";
+ bool first = true;
+ prepare_member_name_mapping(arg_struct);
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << "args." << prop_name(*f_iter);
+ if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+ f_service_ << ".Value";
+ }
+ }
+ cleanup_member_name_mapping(arg_struct);
+ f_service_ << ");" << endl;
+
+ prepare_member_name_mapping(xs, xs->get_members(), resultname);
+ if (xceptions.size() > 0) {
+ indent_down();
+ f_service_ << indent() << "}" << endl;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+ << (*x_iter)->get_name() << ")" << endl
+ << indent() << "{" << endl;
+ if (!tfunction->is_oneway()) {
+ indent_up();
+ f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+ << ";" << endl;
+ indent_down();
+ }
+ f_service_ << indent() << "}" << endl;
+ }
+ }
+ if (!tfunction->is_oneway()) {
+ f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+ << "\", TMessageType.Reply, seqid)); " << endl;
+ f_service_ << indent() << "result.Write(oprot);" << endl;
+ }
+ indent_down();
+
+ cleanup_member_name_mapping(xs);
+
+ f_service_ << indent() << "}" << endl
+ << indent() << "catch (TTransportException)" << endl
+ << indent() << "{" << endl
+ << indent() << " throw;" << endl
+ << indent() << "}" << endl
+ << indent() << "catch (Exception ex)" << endl
+ << indent() << "{" << endl
+ << indent() << " Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+ << indent() << " Console.Error.WriteLine(ex.ToString());" << endl;
+
+ if (tfunction->is_oneway()) {
+ f_service_ << indent() << "}" << endl;
+ } else {
+ f_service_ << indent() << " TApplicationException x = new TApplicationException" << indent()
+ << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+ << endl
+ << indent() << " oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+ << "\", TMessageType.Exception, seqid));" << endl
+ << indent() << " x.Write(oprot);" << endl
+ << indent() << "}" << endl;
+ f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+ << indent() << "oprot.Transport.Flush();" << endl;
+ }
+
+ scope_down(f_service_);
+
+ f_service_ << endl;
+}
+
+void t_csharp_generator::generate_process_function_async(t_service* tservice, t_function* tfunction) {
+ (void)tservice;
+ indent(f_service_) << "public async Task " << tfunction->get_name()
+ << "_ProcessAsync(int seqid, 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_oneway()) {
+ f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+ }
+
+ f_service_ << indent() << "try" << endl
+ << indent() << "{" << endl;
+ indent_up();
+
+ if (xceptions.size() > 0) {
+ f_service_ << indent() << "try" << endl
+ << indent() << "{" << 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_oneway() && !tfunction->get_returntype()->is_void()) {
+ f_service_ << "result.Success = ";
+ }
+ f_service_ << "await iface_." << normalize_name(tfunction->get_name()) << "Async(";
+ bool first = true;
+ prepare_member_name_mapping(arg_struct);
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ }
+ else {
+ f_service_ << ", ";
+ }
+ f_service_ << "args." << prop_name(*f_iter);
+ if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+ f_service_ << ".Value";
+ }
+ }
+ cleanup_member_name_mapping(arg_struct);
+ f_service_ << ");" << endl;
+
+ prepare_member_name_mapping(xs, xs->get_members(), resultname);
+ if (xceptions.size() > 0) {
+ indent_down();
+ f_service_ << indent() << "}" << endl;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+ << (*x_iter)->get_name() << ")" << endl
+ << indent() << "{" << endl;
+ if (!tfunction->is_oneway()) {
+ indent_up();
+ f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+ << ";" << endl;
+ indent_down();
+ }
+ f_service_ << indent() << "}" << endl;
+ }
+ }
+ if (!tfunction->is_oneway()) {
+ f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+ << "\", TMessageType.Reply, seqid)); " << endl;
+ f_service_ << indent() << "result.Write(oprot);" << endl;
+ }
+ indent_down();
+
+ cleanup_member_name_mapping(xs);
+
+ f_service_ << indent() << "}" << endl
+ << indent() << "catch (TTransportException)" << endl
+ << indent() << "{" << endl
+ << indent() << " throw;" << endl
+ << indent() << "}" << endl
+ << indent() << "catch (Exception ex)" << endl
+ << indent() << "{" << endl
+ << indent() << " Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+ << indent() << " Console.Error.WriteLine(ex.ToString());" << endl;
+
+ if (tfunction->is_oneway()) {
+ f_service_ << indent() << "}" << endl;
+ }
+ else {
+ f_service_ << indent() << " TApplicationException x = new TApplicationException" << indent()
+ << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+ << endl
+ << indent() << " oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+ << "\", TMessageType.Exception, seqid));" << endl
+ << indent() << " x.Write(oprot);" << endl
+ << indent() << "}" << endl;
+ f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+ << indent() << "oprot.Transport.Flush();" << endl;
+ }
+
+ scope_down(f_service_);
+
+ f_service_ << endl;
+}
+
+void t_csharp_generator::generate_csharp_union_reader(std::ostream& out, t_struct* tunion) {
+ // Thanks to THRIFT-1768, we don't need to check for required fields in the union
+ const vector<t_field*>& fields = tunion->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl;
+ scope_up(out);
+
+ out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+ out << indent() << "try" << endl;
+ scope_up(out);
+
+ indent(out) << tunion->get_name() << " retval;" << endl;
+ indent(out) << "iprot.ReadStructBegin();" << endl;
+ indent(out) << "TField field = iprot.ReadFieldBegin();" << endl;
+ // we cannot have the first field be a stop -- we must have a single field defined
+ indent(out) << "if (field.Type == TType.Stop)" << endl;
+ scope_up(out);
+ indent(out) << "iprot.ReadFieldEnd();" << endl;
+ indent(out) << "retval = new ___undefined();" << endl;
+ scope_down(out);
+ indent(out) << "else" << endl;
+ scope_up(out);
+ 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();
+
+ indent(out) << type_name((*f_iter)->get_type()) << " temp;" << endl;
+ generate_deserialize_field(out, (*f_iter), "temp", true);
+ indent(out) << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
+
+ indent_down();
+ out << indent() << "} else { " << endl << indent() << " TProtocolUtil.Skip(iprot, field.Type);"
+ << endl << indent() << " retval = new ___undefined();" << endl << indent() << "}" << endl
+ << indent() << "break;" << endl;
+ indent_down();
+ }
+
+ indent(out) << "default: " << endl;
+ indent_up();
+ indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl << indent()
+ << "retval = new ___undefined();" << endl;
+ indent(out) << "break;" << endl;
+ indent_down();
+
+ scope_down(out);
+
+ indent(out) << "iprot.ReadFieldEnd();" << endl;
+
+ indent(out) << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl;
+ scope_up(out);
+ indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
+ scope_down(out);
+
+ // end of else for TStop
+ scope_down(out);
+ indent(out) << "iprot.ReadStructEnd();" << endl;
+ indent(out) << "return retval;" << endl;
+ indent_down();
+
+ scope_down(out);
+ out << indent() << "finally" << endl;
+ scope_up(out);
+ out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+ scope_down(out);
+
+ indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_deserialize_field(ostream& out,
+ t_field* tfield,
+ string prefix,
+ bool is_propertyless) {
+ 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 + (is_propertyless ? "" : prop_name(tfield));
+
+ 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:
+ if (type->is_binary()) {
+ out << "ReadBinary();";
+ } else {
+ out << "ReadString();";
+ }
+ break;
+ case t_base_type::TYPE_BOOL:
+ out << "ReadBool();";
+ break;
+ case t_base_type::TYPE_I8:
+ 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 " + t_base_type::t_base_name(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(ostream& out,
+ t_struct* tstruct,
+ string prefix) {
+ if (union_ && tstruct->is_union()) {
+ out << indent() << prefix << " = " << type_name(tstruct) << ".Read(iprot);" << endl;
+ } else {
+ out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
+ << prefix << ".Read(iprot);" << endl;
+ }
+}
+
+void t_csharp_generator::generate_deserialize_container(ostream& 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(ostream& 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(ostream& out,
+ t_set* tset,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tset->get_elem_type(), elem);
+
+ indent(out) << declare_field(&felem) << endl;
+
+ generate_deserialize_field(out, &felem);
+
+ indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_list_element(ostream& out,
+ t_list* tlist,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tlist->get_elem_type(), elem);
+
+ indent(out) << declare_field(&felem) << endl;
+
+ generate_deserialize_field(out, &felem);
+
+ indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_serialize_field(ostream& out,
+ t_field* tfield,
+ string prefix,
+ bool is_element,
+ bool is_propertyless) {
+ t_type* type = tfield->get_type();
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+ if (type->is_void()) {
+ throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+ }
+
+ if (type->is_struct() || type->is_xception()) {
+ generate_serialize_struct(out, (t_struct*)type, name);
+ } else if (type->is_container()) {
+ generate_serialize_container(out, type, name);
+ } else if (type->is_base_type() || type->is_enum()) {
+ indent(out) << "oprot.";
+
+ string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value"
+ : name;
+
+ 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:
+ if (type->is_binary()) {
+ out << "WriteBinary(";
+ } else {
+ out << "WriteString(";
+ }
+ out << name << ");";
+ break;
+ case t_base_type::TYPE_BOOL:
+ out << "WriteBool(" << nullable_name << ");";
+ break;
+ case t_base_type::TYPE_I8:
+ out << "WriteByte(" << nullable_name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "WriteI16(" << nullable_name << ");";
+ break;
+ case t_base_type::TYPE_I32:
+ out << "WriteI32(" << nullable_name << ");";
+ break;
+ case t_base_type::TYPE_I64:
+ out << "WriteI64(" << nullable_name << ");";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ out << "WriteDouble(" << nullable_name << ");";
+ break;
+ default:
+ throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ out << "WriteI32((int)" << nullable_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(ostream& out,
+ t_struct* tstruct,
+ string prefix) {
+ (void)tstruct;
+ out << indent() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_csharp_generator::generate_serialize_container(ostream& 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);
+ }
+
+ scope_down(out);
+
+ 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);
+}
+
+void t_csharp_generator::generate_serialize_map_element(ostream& out,
+ t_map* tmap,
+ string iter,
+ string map) {
+ t_field kfield(tmap->get_key_type(), iter);
+ generate_serialize_field(out, &kfield, "", true);
+ t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+ generate_serialize_field(out, &vfield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+ t_field efield(tset->get_elem_type(), iter);
+ generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_list_element(ostream& out,
+ t_list* tlist,
+ string iter) {
+ t_field efield(tlist->get_elem_type(), iter);
+ generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_property(ostream& out,
+ t_field* tfield,
+ bool isPublic,
+ bool generateIsset) {
+ generate_csharp_property(out, tfield, isPublic, generateIsset, "_");
+}
+void t_csharp_generator::generate_csharp_property(ostream& out,
+ t_field* tfield,
+ bool isPublic,
+ bool generateIsset,
+ std::string fieldPrefix) {
+ if ((serialize_ || wcf_) && isPublic) {
+ indent(out) << "[DataMember(Order = 0)]" << endl;
+ }
+ bool has_default = field_has_default(tfield);
+ bool is_required = field_is_required(tfield);
+ if ((nullable_ && !has_default) || (is_required)) {
+ indent(out) << (isPublic ? "public " : "private ")
+ << type_name(tfield->get_type(), false, false, true, is_required) << " "
+ << prop_name(tfield) << " { get; set; }" << endl;
+ } else {
+ indent(out) << (isPublic ? "public " : "private ")
+ << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield)
+ << endl;
+ scope_up(out);
+ indent(out) << "get" << endl;
+ scope_up(out);
+ bool use_nullable = false;
+ if (nullable_) {
+ t_type* ttype = tfield->get_type();
+ while (ttype->is_typedef()) {
+ ttype = ((t_typedef*)ttype)->get_type();
+ }
+ if (ttype->is_base_type()) {
+ use_nullable = ((t_base_type*)ttype)->get_base() != t_base_type::TYPE_STRING;
+ } else if (ttype->is_enum()) {
+ use_nullable = true;
+ }
+ }
+ indent(out) << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
+ scope_down(out);
+ indent(out) << "set" << endl;
+ scope_up(out);
+ if (use_nullable) {
+ if (generateIsset) {
+ indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;"
+ << endl;
+ }
+ indent(out) << "if (value.HasValue) this." << fieldPrefix + tfield->get_name()
+ << " = value.Value;" << endl;
+ } else {
+ if (generateIsset) {
+ indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl;
+ }
+ indent(out) << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
+ }
+ scope_down(out);
+ scope_down(out);
+ }
+ out << endl;
+}
+
+std::string t_csharp_generator::make_valid_csharp_identifier(std::string const& fromName) {
+ std::string str = fromName;
+ if (str.empty()) {
+ return str;
+ }
+
+ // tests rely on this
+ assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+ // if the first letter is a number, we add an additional underscore in front of it
+ char c = str.at(0);
+ if (('0' <= c) && (c <= '9')) {
+ str = "_" + str;
+ }
+
+ // following chars: letter, number or underscore
+ for (size_t i = 0; i < str.size(); ++i) {
+ c = str.at(i);
+ if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+ && ('_' != c)) {
+ str.replace(i, 1, "_");
+ }
+ }
+
+ return str;
+}
+
+void t_csharp_generator::cleanup_member_name_mapping(void* scope) {
+ if( member_mapping_scopes.empty()) {
+ throw "internal error: cleanup_member_name_mapping() no scope active";
+ }
+
+ member_mapping_scope& active = member_mapping_scopes.back();
+ if (active.scope_member != scope) {
+ throw "internal error: cleanup_member_name_mapping() called for wrong struct";
+ }
+
+ member_mapping_scopes.pop_back();
+}
+
+string t_csharp_generator::get_mapped_member_name(string name) {
+ if( ! member_mapping_scopes.empty()) {
+ member_mapping_scope& active = member_mapping_scopes.back();
+ map<string, string>::iterator iter = active.mapping_table.find(name);
+ if (active.mapping_table.end() != iter) {
+ return iter->second;
+ }
+ }
+
+ pverbose("no mapping for member %s\n", name.c_str());
+ return name;
+}
+
+void t_csharp_generator::prepare_member_name_mapping(t_struct* tstruct) {
+ prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name());
+}
+
+void t_csharp_generator::prepare_member_name_mapping(void* scope,
+ const vector<t_field*>& members,
+ const string& structname) {
+ // begin new scope
+ member_mapping_scope dummy;
+ dummy.scope_member = 0;
+ member_mapping_scopes.push_back(dummy);
+ member_mapping_scope& active = member_mapping_scopes.back();
+ active.scope_member = scope;
+
+ // current C# generator policy:
+ // - prop names are always rendered with an Uppercase first letter
+ // - struct names are used as given
+ std::set<std::string> used_member_names;
+ vector<t_field*>::const_iterator iter;
+
+ // prevent name conflicts with struct (CS0542 error)
+ used_member_names.insert(structname);
+
+ // prevent name conflicts with known methods (THRIFT-2942)
+ used_member_names.insert("Read");
+ used_member_names.insert("Write");
+
+ for (iter = members.begin(); iter != members.end(); ++iter) {
+ string oldname = (*iter)->get_name();
+ string newname = prop_name(*iter, true);
+ while (true) {
+
+ // new name conflicts with another member
+ if (used_member_names.find(newname) != used_member_names.end()) {
+ pverbose("struct %s: member %s conflicts with another member\n",
+ structname.c_str(),
+ newname.c_str());
+ newname += '_';
+ continue;
+ }
+
+ // add always, this helps us to detect edge cases like
+ // different spellings ("foo" and "Foo") within the same struct
+ pverbose("struct %s: member mapping %s => %s\n",
+ structname.c_str(),
+ oldname.c_str(),
+ newname.c_str());
+ active.mapping_table[oldname] = newname;
+ used_member_names.insert(newname);
+ break;
+ }
+ }
+}
+
+std::string t_csharp_generator::prop_name(t_field* tfield, bool suppress_mapping) {
+ string name(tfield->get_name());
+ if (suppress_mapping) {
+ name[0] = toupper(name[0]);
+ } else {
+ name = get_mapped_member_name(name);
+ }
+ return name;
+}
+
+string t_csharp_generator::type_name(t_type* ttype,
+ bool in_container,
+ bool in_init,
+ bool in_param,
+ bool is_required) {
+ (void)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, in_container, in_param, is_required);
+ } 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 "THashSet<" + 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();
+ string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : "";
+ if (program != NULL && program != program_) {
+ string ns = program->get_namespace("csharp");
+ if (!ns.empty()) {
+ return ns + "." + normalize_name(ttype->get_name()) + postfix;
+ }
+ }
+
+ return normalize_name(ttype->get_name()) + postfix;
+}
+
+string t_csharp_generator::base_type_name(t_base_type* tbase,
+ bool in_container,
+ bool in_param,
+ bool is_required) {
+ (void)in_container;
+ string postfix = (!is_required && nullable_ && in_param) ? "?" : "";
+ switch (tbase->get_base()) {
+ case t_base_type::TYPE_VOID:
+ return "void";
+ case t_base_type::TYPE_STRING:
+ if (tbase->is_binary()) {
+ return "byte[]";
+ } else {
+ return "string";
+ }
+ case t_base_type::TYPE_BOOL:
+ return "bool" + postfix;
+ case t_base_type::TYPE_I8:
+ return "sbyte" + postfix;
+ case t_base_type::TYPE_I16:
+ return "short" + postfix;
+ case t_base_type::TYPE_I32:
+ return "int" + postfix;
+ case t_base_type::TYPE_I64:
+ return "long" + postfix;
+ case t_base_type::TYPE_DOUBLE:
+ return "double" + postfix;
+ default:
+ throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base());
+ }
+}
+
+string t_csharp_generator::declare_field(t_field* tfield, bool init, std::string prefix) {
+ string result = type_name(tfield->get_type()) + " " + prefix + 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() && field_has_default(tfield)) {
+ std::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_I8:
+ 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) + " " + normalize_name(prefix + tfunction->get_name()) + "("
+ + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) {
+ string comma = (tfunction->get_arglist()->get_members().size() > 0 ? ", " : "");
+ return "IAsyncResult " + normalize_name(prefix + tfunction->get_name())
+ + "(AsyncCallback callback, object state" + comma + argument_list(tfunction->get_arglist())
+ + ")";
+}
+
+string t_csharp_generator::function_signature_async_end(t_function* tfunction, string prefix) {
+ t_type* ttype = tfunction->get_returntype();
+ return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name())
+ + "(IAsyncResult asyncResult)";
+}
+
+string t_csharp_generator::function_signature_async(t_function* tfunction, string prefix) {
+ t_type* ttype = tfunction->get_returntype();
+ string task = "Task";
+ if (!ttype->is_void())
+ task += "<" + type_name(ttype) + ">";
+ return task + " " + normalize_name(prefix + tfunction->get_name()) + "Async("
+ + 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()) + " " + normalize_name((*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_I8:
+ 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();
+}
+
+void t_csharp_generator::generate_csharp_docstring_comment(ostream& out, string contents) {
+ generate_docstring_comment(out, "/// <summary>\n", "/// ", contents, "/// </summary>\n");
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_field* field) {
+ if (field->get_type()->is_enum()) {
+ string combined_message = field->get_doc() + "\n<seealso cref=\""
+ + get_enum_class_name(field->get_type()) + "\"/>";
+ generate_csharp_docstring_comment(out, combined_message);
+ } else {
+ generate_csharp_doc(out, (t_doc*)field);
+ }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_doc* tdoc) {
+ if (tdoc->has_doc()) {
+ generate_csharp_docstring_comment(out, tdoc->get_doc());
+ }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_function* tfunction) {
+ if (tfunction->has_doc()) {
+ stringstream ps;
+ const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+ vector<t_field*>::const_iterator p_iter;
+ for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+ t_field* p = *p_iter;
+ ps << "\n<param name=\"" << p->get_name() << "\">";
+ if (p->has_doc()) {
+ std::string str = p->get_doc();
+ str.erase(std::remove(str.begin(), str.end(), '\n'),
+ str.end()); // remove the newlines that appear from the parser
+ ps << str;
+ }
+ ps << "</param>";
+ }
+ generate_docstring_comment(out,
+ "",
+ "/// ",
+ "<summary>\n" + tfunction->get_doc() + "</summary>" + ps.str(),
+ "");
+ }
+}
+
+std::string t_csharp_generator::get_enum_class_name(t_type* type) {
+ string package = "";
+ t_program* program = type->get_program();
+ if (program != NULL && program != program_) {
+ package = program->get_namespace("csharp") + ".";
+ }
+ return package + type->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(
+ csharp,
+ "C#",
+ " async: Adds Async support using Task.Run.\n"
+ " wcf: Adds bindings for WCF to generated classes.\n"
+ " serial: Add serialization support to generated classes.\n"
+ " nullable: Use nullable types for properties.\n"
+ " hashcode: Generate a hashcode and equals implementation for classes.\n"
+ " union: Use new union typing, which includes a static read function for union "
+ "types.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc
index 3059fb1..77afeba 100644
--- a/compiler/cpp/src/thrift/generate/t_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_generator.cc
@@ -234,7 +234,10 @@ t_generator* t_generator_registry::get_generator(t_program* program,
gen_map_t& the_map = get_generator_map();
gen_map_t::iterator iter = the_map.find(language);
- if ((language == "csharp") || (language == "netcore")) {
+ if (language == "csharp") {
+ pwarning(1, "The '%s' target is deprecated. Consider moving to 'netstd' instead.", language.c_str());
+ }
+ else if (language == "netcore") {
failure("The '%s' target is no longer available. Use 'netstd' instead.", language.c_str());
}
else if (language == "as3") {
diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll
index 3773516..bdb4fb0 100644
--- a/compiler/cpp/src/thrift/thriftl.ll
+++ b/compiler/cpp/src/thrift/thriftl.ll
@@ -207,6 +207,7 @@ literal_begin (['\"])
"cpp_include" { return tok_cpp_include; }
"cpp_type" { return tok_cpp_type; }
"java_package" { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ }
+"csharp_namespace" { error_unsupported_namespace_decl("csharp"); /* do nothing */ }
"delphi_namespace" { error_unsupported_namespace_decl("delphi"); /* do nothing */ }
"php_namespace" { error_unsupported_namespace_decl("php"); /* do nothing */ }
"py_module" { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ }
diff --git a/compiler/cpp/tests/CMakeLists.txt b/compiler/cpp/tests/CMakeLists.txt
index 924e167..7798c15 100644
--- a/compiler/cpp/tests/CMakeLists.txt
+++ b/compiler/cpp/tests/CMakeLists.txt
@@ -101,6 +101,7 @@ THRIFT_ADD_COMPILER(as3 "Enable compiler for ActionScript 3" OFF)
THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" OFF)
THRIFT_ADD_COMPILER(cl "Enable compiler for Common LISP" OFF)
THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" OFF)
+THRIFT_ADD_COMPILER(csharp "Enable compiler for C#" OFF)
THRIFT_ADD_COMPILER(d "Enable compiler for D" OFF)
THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" OFF)
THRIFT_ADD_COMPILER(delphi "Enable compiler for Delphi" OFF)
diff --git a/lib/csharp/Makefile.am b/lib/csharp/Makefile.am
new file mode 100644
index 0000000..cc2bbc9
--- /dev/null
+++ b/lib/csharp/Makefile.am
@@ -0,0 +1,114 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SUBDIRS = . test/Multiplex
+
+THRIFTCODE = \
+ src/Collections/THashSet.cs \
+ src/Collections/TCollections.cs \
+ src/Properties/AssemblyInfo.cs \
+ src/Protocol/TAbstractBase.cs \
+ src/Protocol/TBase.cs \
+ src/Protocol/TBase64Utils.cs \
+ src/Protocol/TJSONProtocol.cs \
+ src/Protocol/TProtocolException.cs \
+ src/Protocol/TProtocolFactory.cs \
+ src/Protocol/TList.cs \
+ src/Protocol/TSet.cs \
+ src/Protocol/TMap.cs \
+ src/Protocol/TProtocolUtil.cs \
+ src/Protocol/TMessageType.cs \
+ src/Protocol/TProtocol.cs \
+ src/Protocol/TProtocolDecorator.cs \
+ src/Protocol/TMultiplexedProtocol.cs \
+ src/Protocol/TMultiplexedProcessor.cs \
+ src/Protocol/TType.cs \
+ src/Protocol/TField.cs \
+ src/Protocol/TMessage.cs \
+ src/Protocol/TStruct.cs \
+ src/Protocol/TBinaryProtocol.cs \
+ src/Protocol/TCompactProtocol.cs \
+ src/Server/TThreadedServer.cs \
+ src/Server/TThreadPoolServer.cs \
+ src/Server/TSimpleServer.cs \
+ src/Server/TServer.cs \
+ src/Server/TServerEventHandler.cs \
+ src/Transport/TBufferedTransport.cs \
+ src/Transport/TTransport.cs \
+ src/Transport/TSocket.cs \
+ src/Transport/TSocketVersionizer.cs \
+ src/Transport/TTransportException.cs \
+ src/Transport/TStreamTransport.cs \
+ src/Transport/TFramedTransport.cs \
+ src/Transport/TServerTransport.cs \
+ src/Transport/TServerSocket.cs \
+ src/Transport/TTransportFactory.cs \
+ src/Transport/THttpClient.cs \
+ src/Transport/THttpHandler.cs \
+ src/Transport/TMemoryBuffer.cs \
+ src/Transport/TNamedPipeClientTransport.cs \
+ src/Transport/TNamedPipeServerTransport.cs \
+ src/Transport/TTLSSocket.cs \
+ src/Transport/TTLSServerSocket.cs \
+ src/TProcessor.cs \
+ src/TProcessorFactory.cs \
+ src/TSingletonProcessorFactory.cs \
+ src/TPrototypeProcessorFactory.cs \
+ src/TControllingHandler.cs \
+ src/TException.cs \
+ src/TApplicationException.cs
+
+if MONO_MCS
+export CSC = mcs
+else
+export CSC = gmcs
+endif
+
+if NET_2_0
+export CSC_DEFINES = -d:NET_2_0
+endif
+
+all-local: Thrift.dll Thrift.45.dll
+
+Thrift.dll: $(THRIFTCODE)
+ $(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
+
+Thrift.45.dll: $(THRIFTCODE)
+ $(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
+
+CLEANFILES = \
+ Thrift.dll \
+ Thrift.45.dll
+
+DISTCLEANFILES = \
+ Makefile.in
+
+EXTRA_DIST = \
+ $(THRIFTCODE) \
+ ThriftMSBuildTask \
+ src/Thrift.csproj \
+ src/Thrift.45.csproj \
+ src/Thrift.sln \
+ src/Net35/ExtensionsNet35.cs \
+ src/Transport/TSilverlightSocket.cs \
+ src/Transport/THttpTaskAsyncHandler.cs \
+ src/TAsyncProcessor.cs \
+ test \
+ coding_standards.md \
+ README.md
diff --git a/lib/csharp/README.md b/lib/csharp/README.md
new file mode 100644
index 0000000..5fc14cb
--- /dev/null
+++ b/lib/csharp/README.md
@@ -0,0 +1,32 @@
+Thrift C# Software Library
+
+Deprecation notice
+=======
+
+Per [THRIFT-4723](https://issues.apache.org/jira/browse/THRIFT-4723), both CSharp and Netcore targets are deprecated
+and will be removed with the next release. Migrate to the [NetStd language target](../netstd/README.md) instead.
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+Using Thrift with C#
+====================
+
+Thrift requires Mono >= 1.2.6 or .NET framework >= 3.5
diff --git a/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f5f0000
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+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("MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("ThriftMSBuildTask")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+//@TODO where to put License information?
+
+// 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("0.14.0.*")]
+[assembly: AssemblyFileVersion("0.14.0.*")]
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
new file mode 100644
index 0000000..4e6d301
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
@@ -0,0 +1,246 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+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);
+ //don't recompile if the thrift library has been updated since lastComp
+ FileInfo f = new FileInfo(ThriftLibrary.ItemSpec);
+ string thriftLibTime = f.LastWriteTimeUtc.ToFileTimeUtc().ToString();
+ if (lastComp.CompareTo(thriftLibTime) < 0)
+ {
+ //new thrift library, do a compile
+ lastWrite = thriftLibTime;
+ }
+ else if (lastComp == lastWrite || (lastComp == thriftLibTime && lastComp.CompareTo(lastWrite) > 0))
+ {
+ //the .thrift dir hasn't been written to since last compilation, don't need to do anything
+ LogMessage("ThriftImpl up-to-date", MessageImportance.High);
+ 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))
+ {
+ try
+ {
+ Directory.Delete(genDir, true);
+ }
+ catch { /*eh i tried, just over-write now*/}
+ }
+
+ //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 = "--gen csharp -o " + SafePath(thriftDir) + " -r " + thriftFile;
+ p.StartInfo.UseShellExecute = false;
+ p.StartInfo.CreateNoWindow = true;
+ p.StartInfo.RedirectStandardOutput = false;
+ p.Start();
+ p.WaitForExit();
+ if (p.ExitCode != 0)
+ {
+ LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+ return false;
+ }
+ if (p.ExitCode != 0)
+ {
+ LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+ return false;
+ }
+ }
+
+ 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
index 0000000..2589970
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<Project ToolsVersion="4.0" 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>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>0.14.0.0</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </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>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </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>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </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>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </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>
diff --git a/lib/csharp/coding_standards.md b/lib/csharp/coding_standards.md
new file mode 100644
index 0000000..dc87190
--- /dev/null
+++ b/lib/csharp/coding_standards.md
@@ -0,0 +1,6 @@
+## C# Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [MSDN C# Coding Conventions](http://msdn.microsoft.com/en-us/library/ff926074.aspx)
+ * [C# Coding Guidelines](http://csharpguidelines.codeplex.com/)
diff --git a/lib/csharp/src/Collections/TCollections.cs b/lib/csharp/src/Collections/TCollections.cs
new file mode 100644
index 0000000..84afb6a
--- /dev/null
+++ b/lib/csharp/src/Collections/TCollections.cs
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+using System;
+using System.Collections;
+
+namespace Thrift.Collections
+{
+ public class TCollections
+ {
+ /// <summary>
+ /// This will return true if the two collections are value-wise the same.
+ /// If the collection contains a collection, the collections will be compared using this method.
+ /// </summary>
+ public static bool Equals (IEnumerable first, IEnumerable second)
+ {
+ if (first == null && second == null)
+ {
+ return true;
+ }
+ if (first == null || second == null)
+ {
+ return false;
+ }
+ IEnumerator fiter = first.GetEnumerator ();
+ IEnumerator siter = second.GetEnumerator ();
+
+ bool fnext = fiter.MoveNext ();
+ bool snext = siter.MoveNext ();
+ while (fnext && snext)
+ {
+ IEnumerable fenum = fiter.Current as IEnumerable;
+ IEnumerable senum = siter.Current as IEnumerable;
+ if (fenum != null && senum != null)
+ {
+ if (!Equals(fenum, senum))
+ {
+ return false;
+ }
+ }
+ else if (fenum == null ^ senum == null)
+ {
+ return false;
+ }
+ else if (!Equals(fiter.Current, siter.Current))
+ {
+ return false;
+ }
+ fnext = fiter.MoveNext();
+ snext = siter.MoveNext();
+ }
+
+ return fnext == snext;
+ }
+
+ /// <summary>
+ /// This returns a hashcode based on the value of the enumerable.
+ /// </summary>
+ public static int GetHashCode (IEnumerable enumerable)
+ {
+ if (enumerable == null)
+ {
+ return 0;
+ }
+
+ int hashcode = 0;
+ foreach (object obj in enumerable)
+ {
+ IEnumerable enum2 = obj as IEnumerable;
+ int objHash = enum2 == null ? obj.GetHashCode () : GetHashCode (enum2);
+ unchecked
+ {
+ hashcode = (hashcode * 397) ^ (objHash);
+ }
+ }
+ return hashcode;
+ }
+ }
+}
diff --git a/lib/csharp/src/Collections/THashSet.cs b/lib/csharp/src/Collections/THashSet.cs
new file mode 100644
index 0000000..e29271a
--- /dev/null
+++ b/lib/csharp/src/Collections/THashSet.cs
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+#if SILVERLIGHT
+using System.Runtime.Serialization;
+#endif
+
+namespace Thrift.Collections
+{
+#if SILVERLIGHT
+ [DataContract]
+#else
+ [Serializable]
+#endif
+ public class THashSet<T> : ICollection<T>
+ {
+#if NET_2_0 || SILVERLIGHT
+#if SILVERLIGHT
+ [DataMember]
+#endif
+ TDictSet<T> set = new TDictSet<T>();
+#else
+ HashSet<T> set = new HashSet<T>();
+#endif
+ public int Count
+ {
+ get { return set.Count; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public void Add(T item)
+ {
+ set.Add(item);
+ }
+
+ public void Clear()
+ {
+ set.Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ return set.Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ set.CopyTo(array, arrayIndex);
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return set.GetEnumerator();
+ }
+
+ IEnumerator<T> IEnumerable<T>.GetEnumerator()
+ {
+ return ((IEnumerable<T>)set).GetEnumerator();
+ }
+
+ public bool Remove(T item)
+ {
+ return set.Remove(item);
+ }
+
+#if NET_2_0 || SILVERLIGHT
+#if SILVERLIGHT
+ [DataContract]
+#endif
+ private class TDictSet<V> : ICollection<V>
+ {
+#if SILVERLIGHT
+ [DataMember]
+#endif
+ Dictionary<V, TDictSet<V>> dict = new Dictionary<V, TDictSet<V>>();
+
+ public int Count
+ {
+ get { return dict.Count; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return ((IEnumerable)dict.Keys).GetEnumerator();
+ }
+
+ IEnumerator<V> IEnumerable<V>.GetEnumerator()
+ {
+ return dict.Keys.GetEnumerator();
+ }
+
+ public bool Add(V item)
+ {
+ if (!dict.ContainsKey(item))
+ {
+ dict[item] = this;
+ return true;
+ }
+
+ return false;
+ }
+
+ void ICollection<V>.Add(V item)
+ {
+ Add(item);
+ }
+
+ public void Clear()
+ {
+ dict.Clear();
+ }
+
+ public bool Contains(V item)
+ {
+ return dict.ContainsKey(item);
+ }
+
+ public void CopyTo(V[] array, int arrayIndex)
+ {
+ dict.Keys.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(V item)
+ {
+ return dict.Remove(item);
+ }
+ }
+#endif
+ }
+
+}
diff --git a/lib/csharp/src/Net35/ExtensionsNet35.cs b/lib/csharp/src/Net35/ExtensionsNet35.cs
new file mode 100644
index 0000000..73a4232
--- /dev/null
+++ b/lib/csharp/src/Net35/ExtensionsNet35.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+#if (!NET45)
+namespace Thrift
+{
+ static class StreamExtensionsNet35
+ {
+ // CopyTo() has been added in 4.0
+ public static long CopyTo(this Stream source, Stream target)
+ {
+ byte[] buffer = new byte[8192]; // multiple of 4096
+ long nTotal = 0;
+ while (true)
+ {
+ int nRead = source.Read(buffer, 0, buffer.Length);
+ if (nRead <= 0) // done?
+ return nTotal;
+
+ target.Write(buffer, 0, nRead);
+ nTotal += nRead;
+ }
+ }
+ }
+
+}
+#endif
+
diff --git a/lib/csharp/src/Properties/AssemblyInfo.cs b/lib/csharp/src/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c8f51b5
--- /dev/null
+++ b/lib/csharp/src/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+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("Thrift")]
+[assembly: AssemblyDescription("C# bindings for the Apache Thrift RPC system")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+//@TODO where to put License information?
+
+// 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("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")]
+
+// 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("0.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/lib/csharp/src/Protocol/TAbstractBase.cs b/lib/csharp/src/Protocol/TAbstractBase.cs
new file mode 100644
index 0000000..f5a61cd
--- /dev/null
+++ b/lib/csharp/src/Protocol/TAbstractBase.cs
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Thrift.Protocol
+{
+ public interface TAbstractBase
+ {
+ /// <summary>
+ /// Writes the objects out to the protocol.
+ /// </summary>
+ void Write(TProtocol tProtocol);
+ }
+}
diff --git a/lib/csharp/src/Protocol/TBase.cs b/lib/csharp/src/Protocol/TBase.cs
new file mode 100644
index 0000000..411e4d9
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBase.cs
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Thrift.Protocol
+{
+ public interface TBase : TAbstractBase
+ {
+ /// <summary>
+ /// Reads the TObject from the given input protocol.
+ /// </summary>
+ void Read(TProtocol tProtocol);
+ }
+}
diff --git a/lib/csharp/src/Protocol/TBase64Utils.cs b/lib/csharp/src/Protocol/TBase64Utils.cs
new file mode 100644
index 0000000..9eaaebd
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBase64Utils.cs
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+ internal static class TBase64Utils
+ {
+ internal const string ENCODE_TABLE =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ internal static void encode(byte[] src, int srcOff, int len, byte[] dst,
+ int dstOff)
+ {
+ dst[dstOff] = (byte)ENCODE_TABLE[(src[srcOff] >> 2) & 0x3F];
+ if (len == 3)
+ {
+ dst[dstOff + 1] =
+ (byte)ENCODE_TABLE[
+ ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+ dst[dstOff + 2] =
+ (byte)ENCODE_TABLE[
+ ((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+ dst[dstOff + 3] =
+ (byte)ENCODE_TABLE[src[srcOff + 2] & 0x3F];
+ }
+ else if (len == 2)
+ {
+ dst[dstOff + 1] =
+ (byte)ENCODE_TABLE[
+ ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+ dst[dstOff + 2] =
+ (byte)ENCODE_TABLE[(src[srcOff + 1] << 2) & 0x3C];
+
+ }
+ else
+ { // len == 1) {
+ dst[dstOff + 1] =
+ (byte)ENCODE_TABLE[(src[srcOff] << 4) & 0x30];
+ }
+ }
+
+ private static int[] DECODE_TABLE = {
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
+ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
+ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ };
+
+ internal static void decode(byte[] src, int srcOff, int len, byte[] dst,
+ int dstOff)
+ {
+ dst[dstOff] = (byte)
+ ((DECODE_TABLE[src[srcOff] & 0x0FF] << 2) |
+ (DECODE_TABLE[src[srcOff + 1] & 0x0FF] >> 4));
+ if (len > 2)
+ {
+ dst[dstOff + 1] = (byte)
+ (((DECODE_TABLE[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) |
+ (DECODE_TABLE[src[srcOff + 2] & 0x0FF] >> 2));
+ if (len > 3)
+ {
+ dst[dstOff + 2] = (byte)
+ (((DECODE_TABLE[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) |
+ DECODE_TABLE[src[srcOff + 3] & 0x0FF]);
+ }
+ }
+ }
+
+ }
+}
diff --git a/lib/csharp/src/Protocol/TBinaryProtocol.cs b/lib/csharp/src/Protocol/TBinaryProtocol.cs
new file mode 100644
index 0000000..a4faa94
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBinaryProtocol.cs
@@ -0,0 +1,395 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+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;
+
+ #region BinaryProtocol 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((sbyte)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((sbyte)field.Type);
+ WriteI16(field.ID);
+ }
+
+ public override void WriteFieldEnd()
+ {
+ }
+
+ public override void WriteFieldStop()
+ {
+ WriteByte((sbyte)TType.Stop);
+ }
+
+ public override void WriteMapBegin(TMap map)
+ {
+ WriteByte((sbyte)map.KeyType);
+ WriteByte((sbyte)map.ValueType);
+ WriteI32(map.Count);
+ }
+
+ public override void WriteMapEnd()
+ {
+ }
+
+ public override void WriteListBegin(TList list)
+ {
+ WriteByte((sbyte)list.ElementType);
+ WriteI32(list.Count);
+ }
+
+ public override void WriteListEnd()
+ {
+ }
+
+ public override void WriteSetBegin(TSet set)
+ {
+ WriteByte((sbyte)set.ElementType);
+ WriteI32(set.Count);
+ }
+
+ public override void WriteSetEnd()
+ {
+ }
+
+ public override void WriteBool(bool b)
+ {
+ WriteByte(b ? (sbyte)1 : (sbyte)0);
+ }
+
+ private byte[] bout = new byte[1];
+ public override void WriteByte(sbyte b)
+ {
+ bout[0] = (byte)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)
+ {
+#if !SILVERLIGHT
+ WriteI64(BitConverter.DoubleToInt64Bits(d));
+#else
+ var bytes = BitConverter.GetBytes(d);
+ WriteI64(BitConverter.ToInt64(bytes, 0));
+#endif
+ }
+
+ public override void WriteBinary(byte[] b)
+ {
+ 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 sbyte ReadByte()
+ {
+ ReadAll(bin, 0, 1);
+ return (sbyte)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)));
+ }
+
+#pragma warning disable 675
+
+ private byte[] i64in = new byte[8];
+ public override long ReadI64()
+ {
+ ReadAll(i64in, 0, 8);
+ unchecked
+ {
+ 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)));
+ }
+ }
+
+#pragma warning restore 675
+
+ public override double ReadDouble()
+ {
+#if !SILVERLIGHT
+ return BitConverter.Int64BitsToDouble(ReadI64());
+#else
+ var value = ReadI64();
+ var bytes = BitConverter.GetBytes(value);
+ return BitConverter.ToDouble(bytes, 0);
+#endif
+ }
+
+ public override byte[] ReadBinary()
+ {
+ int size = ReadI32();
+ byte[] buf = new byte[size];
+ trans.ReadAll(buf, 0, size);
+ return buf;
+ }
+ private string ReadStringBody(int size)
+ {
+ byte[] buf = new byte[size];
+ trans.ReadAll(buf, 0, size);
+ return Encoding.UTF8.GetString(buf, 0, buf.Length);
+ }
+
+ private int ReadAll(byte[] buf, int off, int len)
+ {
+ return trans.ReadAll(buf, off, len);
+ }
+
+ #endregion
+ }
+}
diff --git a/lib/csharp/src/Protocol/TCompactProtocol.cs b/lib/csharp/src/Protocol/TCompactProtocol.cs
new file mode 100644
index 0000000..ff67397
--- /dev/null
+++ b/lib/csharp/src/Protocol/TCompactProtocol.cs
@@ -0,0 +1,849 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+ public class TCompactProtocol : TProtocol
+ {
+ private static TStruct ANONYMOUS_STRUCT = new TStruct("");
+ private static TField TSTOP = new TField("", TType.Stop, (short)0);
+
+ private static byte[] ttypeToCompactType = new byte[16];
+
+ private const byte PROTOCOL_ID = 0x82;
+ private const byte VERSION = 1;
+ private const byte VERSION_MASK = 0x1f; // 0001 1111
+ private const byte TYPE_MASK = 0xE0; // 1110 0000
+ private const byte TYPE_BITS = 0x07; // 0000 0111
+ private const int TYPE_SHIFT_AMOUNT = 5;
+
+ /// <summary>
+ /// All of the on-wire type codes.
+ /// </summary>
+ private static class Types
+ {
+ public const byte STOP = 0x00;
+ public const byte BOOLEAN_TRUE = 0x01;
+ public const byte BOOLEAN_FALSE = 0x02;
+ public const byte BYTE = 0x03;
+ public const byte I16 = 0x04;
+ public const byte I32 = 0x05;
+ public const byte I64 = 0x06;
+ public const byte DOUBLE = 0x07;
+ public const byte BINARY = 0x08;
+ public const byte LIST = 0x09;
+ public const byte SET = 0x0A;
+ public const byte MAP = 0x0B;
+ public const byte STRUCT = 0x0C;
+ }
+
+ /// <summary>
+ /// Used to keep track of the last field for the current and previous structs,
+ /// so we can do the delta stuff.
+ /// </summary>
+ private Stack<short> lastField_ = new Stack<short>(15);
+
+ private short lastFieldId_ = 0;
+
+ /// <summary>
+ /// If we encounter a boolean field begin, save the TField here so it can
+ /// have the value incorporated.
+ /// </summary>
+ private Nullable<TField> booleanField_;
+
+ /// <summary>
+ /// If we Read a field header, and it's a boolean field, save the boolean
+ /// value here so that ReadBool can use it.
+ /// </summary>
+ private Nullable<Boolean> boolValue_;
+
+
+ #region CompactProtocol Factory
+
+ public class Factory : TProtocolFactory
+ {
+ public Factory() { }
+
+ public TProtocol GetProtocol(TTransport trans)
+ {
+ return new TCompactProtocol(trans);
+ }
+ }
+
+ #endregion
+
+ public TCompactProtocol(TTransport trans)
+ : base(trans)
+ {
+ ttypeToCompactType[(int)TType.Stop] = Types.STOP;
+ ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE;
+ ttypeToCompactType[(int)TType.Byte] = Types.BYTE;
+ ttypeToCompactType[(int)TType.I16] = Types.I16;
+ ttypeToCompactType[(int)TType.I32] = Types.I32;
+ ttypeToCompactType[(int)TType.I64] = Types.I64;
+ ttypeToCompactType[(int)TType.Double] = Types.DOUBLE;
+ ttypeToCompactType[(int)TType.String] = Types.BINARY;
+ ttypeToCompactType[(int)TType.List] = Types.LIST;
+ ttypeToCompactType[(int)TType.Set] = Types.SET;
+ ttypeToCompactType[(int)TType.Map] = Types.MAP;
+ ttypeToCompactType[(int)TType.Struct] = Types.STRUCT;
+ }
+
+ public void reset()
+ {
+ lastField_.Clear();
+ lastFieldId_ = 0;
+ }
+
+ #region Write Methods
+
+ /// <summary>
+ /// Writes a byte without any possibility of all that field header nonsense.
+ /// Used internally by other writing methods that know they need to Write a byte.
+ /// </summary>
+ private byte[] byteDirectBuffer = new byte[1];
+
+ private void WriteByteDirect(byte b)
+ {
+ byteDirectBuffer[0] = b;
+ trans.Write(byteDirectBuffer);
+ }
+
+ /// <summary>
+ /// Writes a byte without any possibility of all that field header nonsense.
+ /// </summary>
+ private void WriteByteDirect(int n)
+ {
+ WriteByteDirect((byte)n);
+ }
+
+ /// <summary>
+ /// Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ /// TODO: make a permanent buffer like WriteVarint64?
+ /// </summary>
+ byte[] i32buf = new byte[5];
+
+ private void WriteVarint32(uint n)
+ {
+ int idx = 0;
+ while (true)
+ {
+ if ((n & ~0x7F) == 0)
+ {
+ i32buf[idx++] = (byte)n;
+ // WriteByteDirect((byte)n);
+ break;
+ // return;
+ }
+ else
+ {
+ i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
+ // WriteByteDirect((byte)((n & 0x7F) | 0x80));
+ n >>= 7;
+ }
+ }
+ trans.Write(i32buf, 0, idx);
+ }
+
+ /// <summary>
+ /// Write a message header to the wire. Compact Protocol messages contain the
+ /// protocol version so we can migrate forwards in the future if need be.
+ /// </summary>
+ public override void WriteMessageBegin(TMessage message)
+ {
+ WriteByteDirect(PROTOCOL_ID);
+ WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)));
+ WriteVarint32((uint)message.SeqID);
+ WriteString(message.Name);
+ }
+
+ /// <summary>
+ /// Write a struct begin. This doesn't actually put anything on the wire. We
+ /// use it as an opportunity to put special placeholder markers on the field
+ /// stack so we can get the field id deltas correct.
+ /// </summary>
+ public override void WriteStructBegin(TStruct strct)
+ {
+ lastField_.Push(lastFieldId_);
+ lastFieldId_ = 0;
+ }
+
+ /// <summary>
+ /// Write a struct end. This doesn't actually put anything on the wire. We use
+ /// this as an opportunity to pop the last field from the current struct off
+ /// of the field stack.
+ /// </summary>
+ public override void WriteStructEnd()
+ {
+ lastFieldId_ = lastField_.Pop();
+ }
+
+ /// <summary>
+ /// Write a field header containing the field id and field type. If the
+ /// difference between the current field id and the last one is small (< 15),
+ /// then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+ /// field id will follow the type header as a zigzag varint.
+ /// </summary>
+ public override void WriteFieldBegin(TField field)
+ {
+ if (field.Type == TType.Bool)
+ {
+ // we want to possibly include the value, so we'll wait.
+ booleanField_ = field;
+ }
+ else
+ {
+ WriteFieldBeginInternal(field, 0xFF);
+ }
+ }
+
+ /// <summary>
+ /// The workhorse of WriteFieldBegin. It has the option of doing a
+ /// 'type override' of the type header. This is used specifically in the
+ /// boolean field case.
+ /// </summary>
+ private void WriteFieldBeginInternal(TField field, byte typeOverride)
+ {
+ // short lastField = lastField_.Pop();
+
+ // if there's a type override, use that.
+ byte typeToWrite = typeOverride == 0xFF ? getCompactType(field.Type) : typeOverride;
+
+ // check if we can use delta encoding for the field id
+ if (field.ID > lastFieldId_ && field.ID - lastFieldId_ <= 15)
+ {
+ // Write them together
+ WriteByteDirect((field.ID - lastFieldId_) << 4 | typeToWrite);
+ }
+ else
+ {
+ // Write them separate
+ WriteByteDirect(typeToWrite);
+ WriteI16(field.ID);
+ }
+
+ lastFieldId_ = field.ID;
+ // lastField_.push(field.id);
+ }
+
+ /// <summary>
+ /// Write the STOP symbol so we know there are no more fields in this struct.
+ /// </summary>
+ public override void WriteFieldStop()
+ {
+ WriteByteDirect(Types.STOP);
+ }
+
+ /// <summary>
+ /// Write a map header. If the map is empty, omit the key and value type
+ /// headers, as we don't need any additional information to skip it.
+ /// </summary>
+ public override void WriteMapBegin(TMap map)
+ {
+ if (map.Count == 0)
+ {
+ WriteByteDirect(0);
+ }
+ else
+ {
+ WriteVarint32((uint)map.Count);
+ WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType));
+ }
+ }
+
+ /// <summary>
+ /// Write a list header.
+ /// </summary>
+ public override void WriteListBegin(TList list)
+ {
+ WriteCollectionBegin(list.ElementType, list.Count);
+ }
+
+ /// <summary>
+ /// Write a set header.
+ /// </summary>
+ public override void WriteSetBegin(TSet set)
+ {
+ WriteCollectionBegin(set.ElementType, set.Count);
+ }
+
+ /// <summary>
+ /// Write a boolean value. Potentially, this could be a boolean field, in
+ /// which case the field header info isn't written yet. If so, decide what the
+ /// right type header is for the value and then Write the field header.
+ /// Otherwise, Write a single byte.
+ /// </summary>
+ public override void WriteBool(Boolean b)
+ {
+ if (booleanField_ != null)
+ {
+ // we haven't written the field header yet
+ WriteFieldBeginInternal(booleanField_.Value, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+ booleanField_ = null;
+ }
+ else
+ {
+ // we're not part of a field, so just Write the value.
+ WriteByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+ }
+ }
+
+ /// <summary>
+ /// Write a byte. Nothing to see here!
+ /// </summary>
+ public override void WriteByte(sbyte b)
+ {
+ WriteByteDirect((byte)b);
+ }
+
+ /// <summary>
+ /// Write an I16 as a zigzag varint.
+ /// </summary>
+ public override void WriteI16(short i16)
+ {
+ WriteVarint32(intToZigZag(i16));
+ }
+
+ /// <summary>
+ /// Write an i32 as a zigzag varint.
+ /// </summary>
+ public override void WriteI32(int i32)
+ {
+ WriteVarint32(intToZigZag(i32));
+ }
+
+ /// <summary>
+ /// Write an i64 as a zigzag varint.
+ /// </summary>
+ public override void WriteI64(long i64)
+ {
+ WriteVarint64(longToZigzag(i64));
+ }
+
+ /// <summary>
+ /// Write a double to the wire as 8 bytes.
+ /// </summary>
+ public override void WriteDouble(double dub)
+ {
+ byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
+ fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0);
+ trans.Write(data);
+ }
+
+ /// <summary>
+ /// Write a string to the wire with a varint size preceding.
+ /// </summary>
+ public override void WriteString(string str)
+ {
+ byte[] bytes = UTF8Encoding.UTF8.GetBytes(str);
+ WriteBinary(bytes, 0, bytes.Length);
+ }
+
+ /// <summary>
+ /// Write a byte array, using a varint for the size.
+ /// </summary>
+ public override void WriteBinary(byte[] bin)
+ {
+ WriteBinary(bin, 0, bin.Length);
+ }
+
+ private void WriteBinary(byte[] buf, int offset, int length)
+ {
+ WriteVarint32((uint)length);
+ trans.Write(buf, offset, length);
+ }
+
+ //
+ // These methods are called by structs, but don't actually have any wire
+ // output or purpose.
+ //
+
+ public override void WriteMessageEnd() { }
+ public override void WriteMapEnd() { }
+ public override void WriteListEnd() { }
+ public override void WriteSetEnd() { }
+ public override void WriteFieldEnd() { }
+
+ //
+ // Internal writing methods
+ //
+
+ /// <summary>
+ /// Abstract method for writing the start of lists and sets. List and sets on
+ /// the wire differ only by the type indicator.
+ /// </summary>
+ protected void WriteCollectionBegin(TType elemType, int size)
+ {
+ if (size <= 14)
+ {
+ WriteByteDirect(size << 4 | getCompactType(elemType));
+ }
+ else
+ {
+ WriteByteDirect(0xf0 | getCompactType(elemType));
+ WriteVarint32((uint)size);
+ }
+ }
+
+ /// <summary>
+ /// Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ /// </summary>
+ byte[] varint64out = new byte[10];
+ private void WriteVarint64(ulong n)
+ {
+ int idx = 0;
+ while (true)
+ {
+ if ((n & ~(ulong)0x7FL) == 0)
+ {
+ varint64out[idx++] = (byte)n;
+ break;
+ }
+ else
+ {
+ varint64out[idx++] = ((byte)((n & 0x7F) | 0x80));
+ n >>= 7;
+ }
+ }
+ trans.Write(varint64out, 0, idx);
+ }
+
+ /// <summary>
+ /// Convert l into a zigzag long. This allows negative numbers to be
+ /// represented compactly as a varint.
+ /// </summary>
+ private ulong longToZigzag(long n)
+ {
+ return (ulong)(n << 1) ^ (ulong)(n >> 63);
+ }
+
+ /// <summary>
+ /// Convert n into a zigzag int. This allows negative numbers to be
+ /// represented compactly as a varint.
+ /// </summary>
+ private uint intToZigZag(int n)
+ {
+ return (uint)(n << 1) ^ (uint)(n >> 31);
+ }
+
+ /// <summary>
+ /// Convert a long into little-endian bytes in buf starting at off and going
+ /// until off+7.
+ /// </summary>
+ private void fixedLongToBytes(long n, byte[] buf, int off)
+ {
+ buf[off + 0] = (byte)(n & 0xff);
+ buf[off + 1] = (byte)((n >> 8) & 0xff);
+ buf[off + 2] = (byte)((n >> 16) & 0xff);
+ buf[off + 3] = (byte)((n >> 24) & 0xff);
+ buf[off + 4] = (byte)((n >> 32) & 0xff);
+ buf[off + 5] = (byte)((n >> 40) & 0xff);
+ buf[off + 6] = (byte)((n >> 48) & 0xff);
+ buf[off + 7] = (byte)((n >> 56) & 0xff);
+ }
+
+ #endregion
+
+ #region ReadMethods
+
+ /// <summary>
+ /// Read a message header.
+ /// </summary>
+ public override TMessage ReadMessageBegin()
+ {
+ byte protocolId = (byte)ReadByte();
+ if (protocolId != PROTOCOL_ID)
+ {
+ throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X"));
+ }
+ byte versionAndType = (byte)ReadByte();
+ byte version = (byte)(versionAndType & VERSION_MASK);
+ if (version != VERSION)
+ {
+ throw new TProtocolException("Expected version " + VERSION + " but got " + version);
+ }
+ byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+ int seqid = (int)ReadVarint32();
+ string messageName = ReadString();
+ return new TMessage(messageName, (TMessageType)type, seqid);
+ }
+
+ /// <summary>
+ /// Read a struct begin. There's nothing on the wire for this, but it is our
+ /// opportunity to push a new struct begin marker onto the field stack.
+ /// </summary>
+ public override TStruct ReadStructBegin()
+ {
+ lastField_.Push(lastFieldId_);
+ lastFieldId_ = 0;
+ return ANONYMOUS_STRUCT;
+ }
+
+ /// <summary>
+ /// Doesn't actually consume any wire data, just removes the last field for
+ /// this struct from the field stack.
+ /// </summary>
+ public override void ReadStructEnd()
+ {
+ // consume the last field we Read off the wire.
+ lastFieldId_ = lastField_.Pop();
+ }
+
+ /// <summary>
+ /// Read a field header off the wire.
+ /// </summary>
+ public override TField ReadFieldBegin()
+ {
+ byte type = (byte)ReadByte();
+
+ // if it's a stop, then we can return immediately, as the struct is over.
+ if (type == Types.STOP)
+ {
+ return TSTOP;
+ }
+
+ short fieldId;
+
+ // mask off the 4 MSB of the type header. it could contain a field id delta.
+ short modifier = (short)((type & 0xf0) >> 4);
+ if (modifier == 0)
+ {
+ // not a delta. look ahead for the zigzag varint field id.
+ fieldId = ReadI16();
+ }
+ else
+ {
+ // has a delta. add the delta to the last Read field id.
+ fieldId = (short)(lastFieldId_ + modifier);
+ }
+
+ TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
+
+ // if this happens to be a boolean field, the value is encoded in the type
+ if (isBoolType(type))
+ {
+ // save the boolean value in a special instance variable.
+ boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? true : false;
+ }
+
+ // push the new field onto the field stack so we can keep the deltas going.
+ lastFieldId_ = field.ID;
+ return field;
+ }
+
+ /// <summary>
+ /// Read a map header off the wire. If the size is zero, skip Reading the key
+ /// and value type. This means that 0-length maps will yield TMaps without the
+ /// "correct" types.
+ /// </summary>
+ public override TMap ReadMapBegin()
+ {
+ int size = (int)ReadVarint32();
+ byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte();
+ return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
+ }
+
+ /// <summary>
+ /// Read a list header off the wire. If the list size is 0-14, the size will
+ /// be packed into the element type header. If it's a longer list, the 4 MSB
+ /// of the element type header will be 0xF, and a varint will follow with the
+ /// true size.
+ /// </summary>
+ public override TList ReadListBegin()
+ {
+ byte size_and_type = (byte)ReadByte();
+ int size = (size_and_type >> 4) & 0x0f;
+ if (size == 15)
+ {
+ size = (int)ReadVarint32();
+ }
+ TType type = getTType(size_and_type);
+ return new TList(type, size);
+ }
+
+ /// <summary>
+ /// Read a set header off the wire. If the set size is 0-14, the size will
+ /// be packed into the element type header. If it's a longer set, the 4 MSB
+ /// of the element type header will be 0xF, and a varint will follow with the
+ /// true size.
+ /// </summary>
+ public override TSet ReadSetBegin()
+ {
+ return new TSet(ReadListBegin());
+ }
+
+ /// <summary>
+ /// Read a boolean off the wire. If this is a boolean field, the value should
+ /// already have been Read during ReadFieldBegin, so we'll just consume the
+ /// pre-stored value. Otherwise, Read a byte.
+ /// </summary>
+ public override Boolean ReadBool()
+ {
+ if (boolValue_ != null)
+ {
+ bool result = boolValue_.Value;
+ boolValue_ = null;
+ return result;
+ }
+ return ReadByte() == Types.BOOLEAN_TRUE;
+ }
+
+ byte[] byteRawBuf = new byte[1];
+ /// <summary>
+ /// Read a single byte off the wire. Nothing interesting here.
+ /// </summary>
+ public override sbyte ReadByte()
+ {
+ trans.ReadAll(byteRawBuf, 0, 1);
+ return (sbyte)byteRawBuf[0];
+ }
+
+ /// <summary>
+ /// Read an i16 from the wire as a zigzag varint.
+ /// </summary>
+ public override short ReadI16()
+ {
+ return (short)zigzagToInt(ReadVarint32());
+ }
+
+ /// <summary>
+ /// Read an i32 from the wire as a zigzag varint.
+ /// </summary>
+ public override int ReadI32()
+ {
+ return zigzagToInt(ReadVarint32());
+ }
+
+ /// <summary>
+ /// Read an i64 from the wire as a zigzag varint.
+ /// </summary>
+ public override long ReadI64()
+ {
+ return zigzagToLong(ReadVarint64());
+ }
+
+ /// <summary>
+ /// No magic here - just Read a double off the wire.
+ /// </summary>
+ public override double ReadDouble()
+ {
+ byte[] longBits = new byte[8];
+ trans.ReadAll(longBits, 0, 8);
+ return BitConverter.Int64BitsToDouble(bytesToLong(longBits));
+ }
+
+ /// <summary>
+ /// Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+ /// </summary>
+ public override string ReadString()
+ {
+ int length = (int)ReadVarint32();
+
+ if (length == 0)
+ {
+ return "";
+ }
+
+ return Encoding.UTF8.GetString(ReadBinary(length));
+ }
+
+ /// <summary>
+ /// Read a byte[] from the wire.
+ /// </summary>
+ public override byte[] ReadBinary()
+ {
+ int length = (int)ReadVarint32();
+ if (length == 0) return new byte[0];
+
+ byte[] buf = new byte[length];
+ trans.ReadAll(buf, 0, length);
+ return buf;
+ }
+
+ /// <summary>
+ /// Read a byte[] of a known length from the wire.
+ /// </summary>
+ private byte[] ReadBinary(int length)
+ {
+ if (length == 0) return new byte[0];
+
+ byte[] buf = new byte[length];
+ trans.ReadAll(buf, 0, length);
+ return buf;
+ }
+
+ //
+ // These methods are here for the struct to call, but don't have any wire
+ // encoding.
+ //
+ public override void ReadMessageEnd() { }
+ public override void ReadFieldEnd() { }
+ public override void ReadMapEnd() { }
+ public override void ReadListEnd() { }
+ public override void ReadSetEnd() { }
+
+ //
+ // Internal Reading methods
+ //
+
+ /// <summary>
+ /// Read an i32 from the wire as a varint. The MSB of each byte is set
+ /// if there is another byte to follow. This can Read up to 5 bytes.
+ /// </summary>
+ private uint ReadVarint32()
+ {
+ uint result = 0;
+ int shift = 0;
+ while (true)
+ {
+ byte b = (byte)ReadByte();
+ result |= (uint)(b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift += 7;
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Read an i64 from the wire as a proper varint. The MSB of each byte is set
+ /// if there is another byte to follow. This can Read up to 10 bytes.
+ /// </summary>
+ private ulong ReadVarint64()
+ {
+ int shift = 0;
+ ulong result = 0;
+ while (true)
+ {
+ byte b = (byte)ReadByte();
+ result |= (ulong)(b & 0x7f) << shift;
+ if ((b & 0x80) != 0x80) break;
+ shift += 7;
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ //
+ // encoding helpers
+ //
+
+ /// <summary>
+ /// Convert from zigzag int to int.
+ /// </summary>
+ private int zigzagToInt(uint n)
+ {
+ return (int)(n >> 1) ^ (-(int)(n & 1));
+ }
+
+ /// <summary>
+ /// Convert from zigzag long to long.
+ /// </summary>
+ private long zigzagToLong(ulong n)
+ {
+ return (long)(n >> 1) ^ (-(long)(n & 1));
+ }
+
+ /// <summary>
+ /// Note that it's important that the mask bytes are long literals,
+ /// otherwise they'll default to ints, and when you shift an int left 56 bits,
+ /// you just get a messed up int.
+ /// </summary>
+ private long bytesToLong(byte[] bytes)
+ {
+ return
+ ((bytes[7] & 0xffL) << 56) |
+ ((bytes[6] & 0xffL) << 48) |
+ ((bytes[5] & 0xffL) << 40) |
+ ((bytes[4] & 0xffL) << 32) |
+ ((bytes[3] & 0xffL) << 24) |
+ ((bytes[2] & 0xffL) << 16) |
+ ((bytes[1] & 0xffL) << 8) |
+ ((bytes[0] & 0xffL));
+ }
+
+ //
+ // type testing and converting
+ //
+
+ private Boolean isBoolType(byte b)
+ {
+ int lowerNibble = b & 0x0f;
+ return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
+ }
+
+ /// <summary>
+ /// Given a TCompactProtocol.Types constant, convert it to its corresponding
+ /// TType value.
+ /// </summary>
+ private TType getTType(byte type)
+ {
+ switch ((byte)(type & 0x0f))
+ {
+ case Types.STOP:
+ return TType.Stop;
+ case Types.BOOLEAN_FALSE:
+ case Types.BOOLEAN_TRUE:
+ return TType.Bool;
+ case Types.BYTE:
+ return TType.Byte;
+ case Types.I16:
+ return TType.I16;
+ case Types.I32:
+ return TType.I32;
+ case Types.I64:
+ return TType.I64;
+ case Types.DOUBLE:
+ return TType.Double;
+ case Types.BINARY:
+ return TType.String;
+ case Types.LIST:
+ return TType.List;
+ case Types.SET:
+ return TType.Set;
+ case Types.MAP:
+ return TType.Map;
+ case Types.STRUCT:
+ return TType.Struct;
+ default:
+ throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));
+ }
+ }
+
+ /// <summary>
+ /// Given a TType value, find the appropriate TCompactProtocol.Types constant.
+ /// </summary>
+ private byte getCompactType(TType ttype)
+ {
+ return ttypeToCompactType[(int)ttype];
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TField.cs b/lib/csharp/src/Protocol/TField.cs
new file mode 100644
index 0000000..8179557
--- /dev/null
+++ b/lib/csharp/src/Protocol/TField.cs
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TField
+ {
+ private string name;
+ private TType type;
+ private short id;
+
+ public TField(string name, TType type, short id)
+ :this()
+ {
+ this.name = name;
+ this.type = type;
+ this.id = id;
+ }
+
+ public string Name
+ {
+ get { return name; }
+ set { name = value; }
+ }
+
+ public TType Type
+ {
+ get { return type; }
+ set { type = value; }
+ }
+
+ public short ID
+ {
+ get { return id; }
+ set { id = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TJSONProtocol.cs b/lib/csharp/src/Protocol/TJSONProtocol.cs
new file mode 100644
index 0000000..9dbdea9
--- /dev/null
+++ b/lib/csharp/src/Protocol/TJSONProtocol.cs
@@ -0,0 +1,1124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+
+using Thrift.Transport;
+using System.Globalization;
+
+namespace Thrift.Protocol
+{
+ /// <summary>
+ /// JSON protocol implementation for thrift.
+ /// <para/>
+ /// This is a full-featured protocol supporting Write and Read.
+ /// <para/>
+ /// Please see the C++ class header for a detailed description of the
+ /// protocol's wire format.
+ /// <para/>
+ /// Adapted from the Java version.
+ /// </summary>
+ public class TJSONProtocol : TProtocol
+ {
+ /// <summary>
+ /// Factory for JSON protocol objects.
+ /// </summary>
+ public class Factory : TProtocolFactory
+ {
+ public TProtocol GetProtocol(TTransport trans)
+ {
+ return new TJSONProtocol(trans);
+ }
+ }
+
+ private static byte[] COMMA = new byte[] { (byte)',' };
+ private static byte[] COLON = new byte[] { (byte)':' };
+ private static byte[] LBRACE = new byte[] { (byte)'{' };
+ private static byte[] RBRACE = new byte[] { (byte)'}' };
+ private static byte[] LBRACKET = new byte[] { (byte)'[' };
+ private static byte[] RBRACKET = new byte[] { (byte)']' };
+ private static byte[] QUOTE = new byte[] { (byte)'"' };
+ private static byte[] BACKSLASH = new byte[] { (byte)'\\' };
+
+ private byte[] ESCSEQ = new byte[] { (byte)'\\', (byte)'u', (byte)'0', (byte)'0' };
+
+ private const long VERSION = 1;
+ private byte[] JSON_CHAR_TABLE = {
+ 0, 0, 0, 0, 0, 0, 0, 0,(byte)'b',(byte)'t',(byte)'n', 0,(byte)'f',(byte)'r', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1,(byte)'"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ };
+
+ private char[] ESCAPE_CHARS = "\"\\/bfnrt".ToCharArray();
+
+ private byte[] ESCAPE_CHAR_VALS = {
+ (byte)'"', (byte)'\\', (byte)'/', (byte)'\b', (byte)'\f', (byte)'\n', (byte)'\r', (byte)'\t',
+ };
+
+ private const int DEF_STRING_SIZE = 16;
+
+ private static byte[] NAME_BOOL = new byte[] { (byte)'t', (byte)'f' };
+ private static byte[] NAME_BYTE = new byte[] { (byte)'i', (byte)'8' };
+ private static byte[] NAME_I16 = new byte[] { (byte)'i', (byte)'1', (byte)'6' };
+ private static byte[] NAME_I32 = new byte[] { (byte)'i', (byte)'3', (byte)'2' };
+ private static byte[] NAME_I64 = new byte[] { (byte)'i', (byte)'6', (byte)'4' };
+ private static byte[] NAME_DOUBLE = new byte[] { (byte)'d', (byte)'b', (byte)'l' };
+ private static byte[] NAME_STRUCT = new byte[] { (byte)'r', (byte)'e', (byte)'c' };
+ private static byte[] NAME_STRING = new byte[] { (byte)'s', (byte)'t', (byte)'r' };
+ private static byte[] NAME_MAP = new byte[] { (byte)'m', (byte)'a', (byte)'p' };
+ private static byte[] NAME_LIST = new byte[] { (byte)'l', (byte)'s', (byte)'t' };
+ private static byte[] NAME_SET = new byte[] { (byte)'s', (byte)'e', (byte)'t' };
+
+ private static byte[] GetTypeNameForTypeID(TType typeID)
+ {
+ switch (typeID)
+ {
+ case TType.Bool:
+ return NAME_BOOL;
+ case TType.Byte:
+ return NAME_BYTE;
+ case TType.I16:
+ return NAME_I16;
+ case TType.I32:
+ return NAME_I32;
+ case TType.I64:
+ return NAME_I64;
+ case TType.Double:
+ return NAME_DOUBLE;
+ case TType.String:
+ return NAME_STRING;
+ case TType.Struct:
+ return NAME_STRUCT;
+ case TType.Map:
+ return NAME_MAP;
+ case TType.Set:
+ return NAME_SET;
+ case TType.List:
+ return NAME_LIST;
+ default:
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Unrecognized type");
+ }
+ }
+
+ private static TType GetTypeIDForTypeName(byte[] name)
+ {
+ TType result = TType.Stop;
+ if (name.Length > 1)
+ {
+ switch (name[0])
+ {
+ case (byte)'d':
+ result = TType.Double;
+ break;
+ case (byte)'i':
+ switch (name[1])
+ {
+ case (byte)'8':
+ result = TType.Byte;
+ break;
+ case (byte)'1':
+ result = TType.I16;
+ break;
+ case (byte)'3':
+ result = TType.I32;
+ break;
+ case (byte)'6':
+ result = TType.I64;
+ break;
+ }
+ break;
+ case (byte)'l':
+ result = TType.List;
+ break;
+ case (byte)'m':
+ result = TType.Map;
+ break;
+ case (byte)'r':
+ result = TType.Struct;
+ break;
+ case (byte)'s':
+ if (name[1] == (byte)'t')
+ {
+ result = TType.String;
+ }
+ else if (name[1] == (byte)'e')
+ {
+ result = TType.Set;
+ }
+ break;
+ case (byte)'t':
+ result = TType.Bool;
+ break;
+ }
+ }
+ if (result == TType.Stop)
+ {
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+ "Unrecognized type");
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Base class for tracking JSON contexts that may require
+ /// inserting/Reading additional JSON syntax characters
+ /// This base context does nothing.
+ /// </summary>
+ protected class JSONBaseContext
+ {
+ protected TJSONProtocol proto;
+
+ public JSONBaseContext(TJSONProtocol proto)
+ {
+ this.proto = proto;
+ }
+
+ public virtual void Write() { }
+
+ public virtual void Read() { }
+
+ public virtual bool EscapeNumbers() { return false; }
+ }
+
+ /// <summary>
+ /// Context for JSON lists. Will insert/Read commas before each item except
+ /// for the first one
+ /// </summary>
+ protected class JSONListContext : JSONBaseContext
+ {
+ public JSONListContext(TJSONProtocol protocol)
+ : base(protocol)
+ {
+
+ }
+
+ private bool first = true;
+
+ public override void Write()
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ proto.trans.Write(COMMA);
+ }
+ }
+
+ public override void Read()
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ proto.ReadJSONSyntaxChar(COMMA);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Context for JSON records. Will insert/Read colons before the value portion
+ /// of each record pair, and commas before each key except the first. In
+ /// addition, will indicate that numbers in the key position need to be
+ /// escaped in quotes (since JSON keys must be strings).
+ /// </summary>
+ protected class JSONPairContext : JSONBaseContext
+ {
+ public JSONPairContext(TJSONProtocol proto)
+ : base(proto)
+ {
+
+ }
+
+ private bool first = true;
+ private bool colon = true;
+
+ public override void Write()
+ {
+ if (first)
+ {
+ first = false;
+ colon = true;
+ }
+ else
+ {
+ proto.trans.Write(colon ? COLON : COMMA);
+ colon = !colon;
+ }
+ }
+
+ public override void Read()
+ {
+ if (first)
+ {
+ first = false;
+ colon = true;
+ }
+ else
+ {
+ proto.ReadJSONSyntaxChar(colon ? COLON : COMMA);
+ colon = !colon;
+ }
+ }
+
+ public override bool EscapeNumbers()
+ {
+ return colon;
+ }
+ }
+
+ /// <summary>
+ /// Holds up to one byte from the transport
+ /// </summary>
+ protected class LookaheadReader
+ {
+ protected TJSONProtocol proto;
+
+ public LookaheadReader(TJSONProtocol proto)
+ {
+ this.proto = proto;
+ }
+
+ private bool hasData;
+ private byte[] data = new byte[1];
+
+ /// <summary>
+ /// Return and consume the next byte to be Read, either taking it from the
+ /// data buffer if present or getting it from the transport otherwise.
+ /// </summary>
+ public byte Read()
+ {
+ if (hasData)
+ {
+ hasData = false;
+ }
+ else
+ {
+ proto.trans.ReadAll(data, 0, 1);
+ }
+ return data[0];
+ }
+
+ /// <summary>
+ /// Return the next byte to be Read without consuming, filling the data
+ /// buffer if it has not been filled alReady.
+ /// </summary>
+ public byte Peek()
+ {
+ if (!hasData)
+ {
+ proto.trans.ReadAll(data, 0, 1);
+ }
+ hasData = true;
+ return data[0];
+ }
+ }
+
+ // Default encoding
+ protected Encoding utf8Encoding = UTF8Encoding.UTF8;
+
+ // Stack of nested contexts that we may be in
+ protected Stack<JSONBaseContext> contextStack = new Stack<JSONBaseContext>();
+
+ // Current context that we are in
+ protected JSONBaseContext context;
+
+ // Reader that manages a 1-byte buffer
+ protected LookaheadReader reader;
+
+ /// <summary>
+ /// Push a new JSON context onto the stack.
+ /// </summary>
+ protected void PushContext(JSONBaseContext c)
+ {
+ contextStack.Push(context);
+ context = c;
+ }
+
+ /// <summary>
+ /// Pop the last JSON context off the stack
+ /// </summary>
+ protected void PopContext()
+ {
+ context = contextStack.Pop();
+ }
+
+ /// <summary>
+ /// TJSONProtocol Constructor
+ /// </summary>
+ public TJSONProtocol(TTransport trans)
+ : base(trans)
+ {
+ context = new JSONBaseContext(this);
+ reader = new LookaheadReader(this);
+ }
+
+ // Temporary buffer used by several methods
+ private byte[] tempBuffer = new byte[4];
+
+ /// <summary>
+ /// Read a byte that must match b[0]; otherwise an exception is thrown.
+ /// Marked protected to avoid synthetic accessor in JSONListContext.Read
+ /// and JSONPairContext.Read
+ /// </summary>
+ protected void ReadJSONSyntaxChar(byte[] b)
+ {
+ byte ch = reader.Read();
+ if (ch != b[0])
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Unexpected character:" + (char)ch);
+ }
+ }
+
+ /// <summary>
+ /// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+ /// corresponding hex value
+ /// </summary>
+ private static byte HexVal(byte ch)
+ {
+ if ((ch >= '0') && (ch <= '9'))
+ {
+ return (byte)((char)ch - '0');
+ }
+ else if ((ch >= 'a') && (ch <= 'f'))
+ {
+ ch += 10;
+ return (byte)((char)ch - 'a');
+ }
+ else
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected hex character");
+ }
+ }
+
+ /// <summary>
+ /// Convert a byte containing a hex value to its corresponding hex character
+ /// </summary>
+ private static byte HexChar(byte val)
+ {
+ val &= 0x0F;
+ if (val < 10)
+ {
+ return (byte)((char)val + '0');
+ }
+ else
+ {
+ val -= 10;
+ return (byte)((char)val + 'a');
+ }
+ }
+
+ /// <summary>
+ /// Write the bytes in array buf as a JSON characters, escaping as needed
+ /// </summary>
+ private void WriteJSONString(byte[] b)
+ {
+ context.Write();
+ trans.Write(QUOTE);
+ int len = b.Length;
+ for (int i = 0; i < len; i++)
+ {
+ if ((b[i] & 0x00FF) >= 0x30)
+ {
+ if (b[i] == BACKSLASH[0])
+ {
+ trans.Write(BACKSLASH);
+ trans.Write(BACKSLASH);
+ }
+ else
+ {
+ trans.Write(b, i, 1);
+ }
+ }
+ else
+ {
+ tempBuffer[0] = JSON_CHAR_TABLE[b[i]];
+ if (tempBuffer[0] == 1)
+ {
+ trans.Write(b, i, 1);
+ }
+ else if (tempBuffer[0] > 1)
+ {
+ trans.Write(BACKSLASH);
+ trans.Write(tempBuffer, 0, 1);
+ }
+ else
+ {
+ trans.Write(ESCSEQ);
+ tempBuffer[0] = HexChar((byte)(b[i] >> 4));
+ tempBuffer[1] = HexChar(b[i]);
+ trans.Write(tempBuffer, 0, 2);
+ }
+ }
+ }
+ trans.Write(QUOTE);
+ }
+
+ /// <summary>
+ /// Write out number as a JSON value. If the context dictates so, it will be
+ /// wrapped in quotes to output as a JSON string.
+ /// </summary>
+ private void WriteJSONInteger(long num)
+ {
+ context.Write();
+ string str = num.ToString();
+
+ bool escapeNum = context.EscapeNumbers();
+ if (escapeNum)
+ trans.Write(QUOTE);
+
+ trans.Write(utf8Encoding.GetBytes(str));
+
+ if (escapeNum)
+ trans.Write(QUOTE);
+ }
+
+ /// <summary>
+ /// Write out a double as a JSON value. If it is NaN or infinity or if the
+ /// context dictates escaping, Write out as JSON string.
+ /// </summary>
+ private void WriteJSONDouble(double num)
+ {
+ context.Write();
+ string str = num.ToString("G17", CultureInfo.InvariantCulture);
+ bool special = false;
+
+ switch (str[0])
+ {
+ case 'N': // NaN
+ case 'I': // Infinity
+ special = true;
+ break;
+ case '-':
+ if (str[1] == 'I')
+ { // -Infinity
+ special = true;
+ }
+ break;
+ }
+
+ bool escapeNum = special || context.EscapeNumbers();
+
+ if (escapeNum)
+ trans.Write(QUOTE);
+
+ trans.Write(utf8Encoding.GetBytes(str));
+
+ if (escapeNum)
+ trans.Write(QUOTE);
+ }
+ /// <summary>
+ /// Write out contents of byte array b as a JSON string with base-64 encoded
+ /// data
+ /// </summary>
+ private void WriteJSONBase64(byte[] b)
+ {
+ context.Write();
+ trans.Write(QUOTE);
+
+ int len = b.Length;
+ int off = 0;
+
+ while (len >= 3)
+ {
+ // Encode 3 bytes at a time
+ TBase64Utils.encode(b, off, 3, tempBuffer, 0);
+ trans.Write(tempBuffer, 0, 4);
+ off += 3;
+ len -= 3;
+ }
+ if (len > 0)
+ {
+ // Encode remainder
+ TBase64Utils.encode(b, off, len, tempBuffer, 0);
+ trans.Write(tempBuffer, 0, len + 1);
+ }
+
+ trans.Write(QUOTE);
+ }
+
+ private void WriteJSONObjectStart()
+ {
+ context.Write();
+ trans.Write(LBRACE);
+ PushContext(new JSONPairContext(this));
+ }
+
+ private void WriteJSONObjectEnd()
+ {
+ PopContext();
+ trans.Write(RBRACE);
+ }
+
+ private void WriteJSONArrayStart()
+ {
+ context.Write();
+ trans.Write(LBRACKET);
+ PushContext(new JSONListContext(this));
+ }
+
+ private void WriteJSONArrayEnd()
+ {
+ PopContext();
+ trans.Write(RBRACKET);
+ }
+
+ public override void WriteMessageBegin(TMessage message)
+ {
+ WriteJSONArrayStart();
+ WriteJSONInteger(VERSION);
+
+ byte[] b = utf8Encoding.GetBytes(message.Name);
+ WriteJSONString(b);
+
+ WriteJSONInteger((long)message.Type);
+ WriteJSONInteger(message.SeqID);
+ }
+
+ public override void WriteMessageEnd()
+ {
+ WriteJSONArrayEnd();
+ }
+
+ public override void WriteStructBegin(TStruct str)
+ {
+ WriteJSONObjectStart();
+ }
+
+ public override void WriteStructEnd()
+ {
+ WriteJSONObjectEnd();
+ }
+
+ public override void WriteFieldBegin(TField field)
+ {
+ WriteJSONInteger(field.ID);
+ WriteJSONObjectStart();
+ WriteJSONString(GetTypeNameForTypeID(field.Type));
+ }
+
+ public override void WriteFieldEnd()
+ {
+ WriteJSONObjectEnd();
+ }
+
+ public override void WriteFieldStop() { }
+
+ public override void WriteMapBegin(TMap map)
+ {
+ WriteJSONArrayStart();
+ WriteJSONString(GetTypeNameForTypeID(map.KeyType));
+ WriteJSONString(GetTypeNameForTypeID(map.ValueType));
+ WriteJSONInteger(map.Count);
+ WriteJSONObjectStart();
+ }
+
+ public override void WriteMapEnd()
+ {
+ WriteJSONObjectEnd();
+ WriteJSONArrayEnd();
+ }
+
+ public override void WriteListBegin(TList list)
+ {
+ WriteJSONArrayStart();
+ WriteJSONString(GetTypeNameForTypeID(list.ElementType));
+ WriteJSONInteger(list.Count);
+ }
+
+ public override void WriteListEnd()
+ {
+ WriteJSONArrayEnd();
+ }
+
+ public override void WriteSetBegin(TSet set)
+ {
+ WriteJSONArrayStart();
+ WriteJSONString(GetTypeNameForTypeID(set.ElementType));
+ WriteJSONInteger(set.Count);
+ }
+
+ public override void WriteSetEnd()
+ {
+ WriteJSONArrayEnd();
+ }
+
+ public override void WriteBool(bool b)
+ {
+ WriteJSONInteger(b ? (long)1 : (long)0);
+ }
+
+ public override void WriteByte(sbyte b)
+ {
+ WriteJSONInteger((long)b);
+ }
+
+ public override void WriteI16(short i16)
+ {
+ WriteJSONInteger((long)i16);
+ }
+
+ public override void WriteI32(int i32)
+ {
+ WriteJSONInteger((long)i32);
+ }
+
+ public override void WriteI64(long i64)
+ {
+ WriteJSONInteger(i64);
+ }
+
+ public override void WriteDouble(double dub)
+ {
+ WriteJSONDouble(dub);
+ }
+
+ public override void WriteString(string str)
+ {
+ byte[] b = utf8Encoding.GetBytes(str);
+ WriteJSONString(b);
+ }
+
+ public override void WriteBinary(byte[] bin)
+ {
+ WriteJSONBase64(bin);
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ /// <summary>
+ /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the
+ /// context if skipContext is true.
+ /// </summary>
+ private byte[] ReadJSONString(bool skipContext)
+ {
+ MemoryStream buffer = new MemoryStream();
+ List<char> codeunits = new List<char>();
+
+
+ if (!skipContext)
+ {
+ context.Read();
+ }
+ ReadJSONSyntaxChar(QUOTE);
+ while (true)
+ {
+ byte ch = reader.Read();
+ if (ch == QUOTE[0])
+ {
+ break;
+ }
+
+ // escaped?
+ if (ch != ESCSEQ[0])
+ {
+ buffer.Write(new byte[] { (byte)ch }, 0, 1);
+ continue;
+ }
+
+ // distinguish between \uXXXX and \?
+ ch = reader.Read();
+ if (ch != ESCSEQ[1]) // control chars like \n
+ {
+ int off = Array.IndexOf(ESCAPE_CHARS, (char)ch);
+ if (off == -1)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected control char");
+ }
+ ch = ESCAPE_CHAR_VALS[off];
+ buffer.Write(new byte[] { (byte)ch }, 0, 1);
+ continue;
+ }
+
+
+ // it's \uXXXX
+ trans.ReadAll(tempBuffer, 0, 4);
+ var wch = (short)((HexVal((byte)tempBuffer[0]) << 12) +
+ (HexVal((byte)tempBuffer[1]) << 8) +
+ (HexVal((byte)tempBuffer[2]) << 4) +
+ HexVal(tempBuffer[3]));
+ if (Char.IsHighSurrogate((char)wch))
+ {
+ if (codeunits.Count > 0)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected low surrogate char");
+ }
+ codeunits.Add((char)wch);
+ }
+ else if (Char.IsLowSurrogate((char)wch))
+ {
+ if (codeunits.Count == 0)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected high surrogate char");
+ }
+ codeunits.Add((char)wch);
+ var tmp = utf8Encoding.GetBytes(codeunits.ToArray());
+ buffer.Write(tmp, 0, tmp.Length);
+ codeunits.Clear();
+ }
+ else
+ {
+ var tmp = utf8Encoding.GetBytes(new char[] { (char)wch });
+ buffer.Write(tmp, 0, tmp.Length);
+ }
+ }
+
+
+ if (codeunits.Count > 0)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Expected low surrogate char");
+ }
+
+ return buffer.ToArray();
+ }
+
+ /// <summary>
+ /// Return true if the given byte could be a valid part of a JSON number.
+ /// </summary>
+ private bool IsJSONNumeric(byte b)
+ {
+ switch (b)
+ {
+ case (byte)'+':
+ case (byte)'-':
+ case (byte)'.':
+ case (byte)'0':
+ case (byte)'1':
+ case (byte)'2':
+ case (byte)'3':
+ case (byte)'4':
+ case (byte)'5':
+ case (byte)'6':
+ case (byte)'7':
+ case (byte)'8':
+ case (byte)'9':
+ case (byte)'E':
+ case (byte)'e':
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Read in a sequence of characters that are all valid in JSON numbers. Does
+ /// not do a complete regex check to validate that this is actually a number.
+ /// </summary>
+ private string ReadJSONNumericChars()
+ {
+ StringBuilder strbld = new StringBuilder();
+ while (true)
+ {
+ byte ch = reader.Peek();
+ if (!IsJSONNumeric(ch))
+ {
+ break;
+ }
+ strbld.Append((char)reader.Read());
+ }
+ return strbld.ToString();
+ }
+
+ /// <summary>
+ /// Read in a JSON number. If the context dictates, Read in enclosing quotes.
+ /// </summary>
+ private long ReadJSONInteger()
+ {
+ context.Read();
+ if (context.EscapeNumbers())
+ {
+ ReadJSONSyntaxChar(QUOTE);
+ }
+
+ string str = ReadJSONNumericChars();
+ if (context.EscapeNumbers())
+ {
+ ReadJSONSyntaxChar(QUOTE);
+ }
+
+ try
+ {
+ return Int64.Parse(str);
+ }
+ catch (FormatException fex)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Bad data encounted in numeric data", fex);
+ }
+ }
+
+ /// <summary>
+ /// Read in a JSON double value. Throw if the value is not wrapped in quotes
+ /// when expected or if wrapped in quotes when not expected.
+ /// </summary>
+ private double ReadJSONDouble()
+ {
+ context.Read();
+ if (reader.Peek() == QUOTE[0])
+ {
+ byte[] arr = ReadJSONString(true);
+ double dub = Double.Parse(utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture);
+
+ if (!context.EscapeNumbers() && !Double.IsNaN(dub) && !Double.IsInfinity(dub))
+ {
+ // Throw exception -- we should not be in a string in this case
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Numeric data unexpectedly quoted");
+ }
+ return dub;
+ }
+ else
+ {
+ if (context.EscapeNumbers())
+ {
+ // This will throw - we should have had a quote if escapeNum == true
+ ReadJSONSyntaxChar(QUOTE);
+ }
+ try
+ {
+ return Double.Parse(ReadJSONNumericChars(), CultureInfo.InvariantCulture);
+ }
+ catch (FormatException fex)
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ "Bad data encounted in numeric data", fex);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Read in a JSON string containing base-64 encoded data and decode it.
+ /// </summary>
+ private byte[] ReadJSONBase64()
+ {
+ byte[] b = ReadJSONString(false);
+ int len = b.Length;
+ int off = 0;
+ int size = 0;
+ // reduce len to ignore fill bytes
+ while ((len > 0) && (b[len - 1] == '='))
+ {
+ --len;
+ }
+ // read & decode full byte triplets = 4 source bytes
+ while (len > 4)
+ {
+ // Decode 4 bytes at a time
+ TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
+ off += 4;
+ len -= 4;
+ size += 3;
+ }
+ // Don't decode if we hit the end or got a single leftover byte (invalid
+ // base64 but legal for skip of regular string type)
+ if (len > 1)
+ {
+ // Decode remainder
+ TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
+ size += len - 1;
+ }
+ // Sadly we must copy the byte[] (any way around this?)
+ byte[] result = new byte[size];
+ Array.Copy(b, 0, result, 0, size);
+ return result;
+ }
+
+ private void ReadJSONObjectStart()
+ {
+ context.Read();
+ ReadJSONSyntaxChar(LBRACE);
+ PushContext(new JSONPairContext(this));
+ }
+
+ private void ReadJSONObjectEnd()
+ {
+ ReadJSONSyntaxChar(RBRACE);
+ PopContext();
+ }
+
+ private void ReadJSONArrayStart()
+ {
+ context.Read();
+ ReadJSONSyntaxChar(LBRACKET);
+ PushContext(new JSONListContext(this));
+ }
+
+ private void ReadJSONArrayEnd()
+ {
+ ReadJSONSyntaxChar(RBRACKET);
+ PopContext();
+ }
+
+ public override TMessage ReadMessageBegin()
+ {
+ TMessage message = new TMessage();
+ ReadJSONArrayStart();
+ if (ReadJSONInteger() != VERSION)
+ {
+ throw new TProtocolException(TProtocolException.BAD_VERSION,
+ "Message contained bad version.");
+ }
+
+ var buf = ReadJSONString(false);
+ message.Name = utf8Encoding.GetString(buf, 0, buf.Length);
+ message.Type = (TMessageType)ReadJSONInteger();
+ message.SeqID = (int)ReadJSONInteger();
+ return message;
+ }
+
+ public override void ReadMessageEnd()
+ {
+ ReadJSONArrayEnd();
+ }
+
+ public override TStruct ReadStructBegin()
+ {
+ ReadJSONObjectStart();
+ return new TStruct();
+ }
+
+ public override void ReadStructEnd()
+ {
+ ReadJSONObjectEnd();
+ }
+
+ public override TField ReadFieldBegin()
+ {
+ TField field = new TField();
+ byte ch = reader.Peek();
+ if (ch == RBRACE[0])
+ {
+ field.Type = TType.Stop;
+ }
+ else
+ {
+ field.ID = (short)ReadJSONInteger();
+ ReadJSONObjectStart();
+ field.Type = GetTypeIDForTypeName(ReadJSONString(false));
+ }
+ return field;
+ }
+
+ public override void ReadFieldEnd()
+ {
+ ReadJSONObjectEnd();
+ }
+
+ public override TMap ReadMapBegin()
+ {
+ TMap map = new TMap();
+ ReadJSONArrayStart();
+ map.KeyType = GetTypeIDForTypeName(ReadJSONString(false));
+ map.ValueType = GetTypeIDForTypeName(ReadJSONString(false));
+ map.Count = (int)ReadJSONInteger();
+ ReadJSONObjectStart();
+ return map;
+ }
+
+ public override void ReadMapEnd()
+ {
+ ReadJSONObjectEnd();
+ ReadJSONArrayEnd();
+ }
+
+ public override TList ReadListBegin()
+ {
+ TList list = new TList();
+ ReadJSONArrayStart();
+ list.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+ list.Count = (int)ReadJSONInteger();
+ return list;
+ }
+
+ public override void ReadListEnd()
+ {
+ ReadJSONArrayEnd();
+ }
+
+ public override TSet ReadSetBegin()
+ {
+ TSet set = new TSet();
+ ReadJSONArrayStart();
+ set.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+ set.Count = (int)ReadJSONInteger();
+ return set;
+ }
+
+ public override void ReadSetEnd()
+ {
+ ReadJSONArrayEnd();
+ }
+
+ public override bool ReadBool()
+ {
+ return (ReadJSONInteger() == 0 ? false : true);
+ }
+
+ public override sbyte ReadByte()
+ {
+ return (sbyte)ReadJSONInteger();
+ }
+
+ public override short ReadI16()
+ {
+ return (short)ReadJSONInteger();
+ }
+
+ public override int ReadI32()
+ {
+ return (int)ReadJSONInteger();
+ }
+
+ public override long ReadI64()
+ {
+ return (long)ReadJSONInteger();
+ }
+
+ public override double ReadDouble()
+ {
+ return ReadJSONDouble();
+ }
+
+ public override string ReadString()
+ {
+ var buf = ReadJSONString(false);
+ return utf8Encoding.GetString(buf, 0, buf.Length);
+ }
+
+ public override byte[] ReadBinary()
+ {
+ return ReadJSONBase64();
+ }
+
+ }
+}
diff --git a/lib/csharp/src/Protocol/TList.cs b/lib/csharp/src/Protocol/TList.cs
new file mode 100644
index 0000000..0c8f214
--- /dev/null
+++ b/lib/csharp/src/Protocol/TList.cs
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TList
+ {
+ private TType elementType;
+ private int count;
+
+ public TList(TType elementType, int count)
+ :this()
+ {
+ this.elementType = elementType;
+ this.count = count;
+ }
+
+ public TType ElementType
+ {
+ get { return elementType; }
+ set { elementType = value; }
+ }
+
+ public int Count
+ {
+ get { return count; }
+ set { count = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TMap.cs b/lib/csharp/src/Protocol/TMap.cs
new file mode 100644
index 0000000..aba9d3a
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMap.cs
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TMap
+ {
+ private TType keyType;
+ private TType valueType;
+ private int count;
+
+ public TMap(TType keyType, TType valueType, int count)
+ :this()
+ {
+ this.keyType = keyType;
+ this.valueType = valueType;
+ this.count = count;
+ }
+
+ public TType KeyType
+ {
+ get { return keyType; }
+ set { keyType = value; }
+ }
+
+ public TType ValueType
+ {
+ get { return valueType; }
+ set { valueType = value; }
+ }
+
+ public int Count
+ {
+ get { return count; }
+ set { count = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TMessage.cs b/lib/csharp/src/Protocol/TMessage.cs
new file mode 100644
index 0000000..348263c
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMessage.cs
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TMessage
+ {
+ private string name;
+ private TMessageType type;
+ private int seqID;
+
+ public TMessage(string name, TMessageType type, int seqid)
+ :this()
+ {
+ this.name = name;
+ this.type = type;
+ this.seqID = seqid;
+ }
+
+ public string Name
+ {
+ get { return name; }
+ set { name = value; }
+ }
+
+ public TMessageType Type
+ {
+ get { return type; }
+ set { type = value; }
+ }
+
+ public int SeqID
+ {
+ get { return seqID; }
+ set { seqID = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TMessageType.cs b/lib/csharp/src/Protocol/TMessageType.cs
new file mode 100644
index 0000000..c7091fe
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMessageType.cs
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+ public enum TMessageType
+ {
+ Call = 1,
+ Reply = 2,
+ Exception = 3,
+ Oneway = 4
+ }
+}
diff --git a/lib/csharp/src/Protocol/TMultiplexedProcessor.cs b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
new file mode 100644
index 0000000..aa91c52
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Thrift.Protocol
+{
+ /// <summary>
+ /// <see cref="TMultiplexedProcessor"/> is a <see cref="TProcessor"/> allowing a single <see cref="Thrift.Server.TServer"/>
+ /// to provide multiple services.
+ /// <para/>
+ /// To do so, you instantiate the processor and then register additional processors with it,
+ /// as shown in the following example:
+ /// <para/>
+ /// <code>
+ /// TMultiplexedProcessor processor = new TMultiplexedProcessor();
+ ///
+ /// processor.registerProcessor(
+ /// "Calculator",
+ /// new Calculator.Processor(new CalculatorHandler()));
+ ///
+ /// processor.registerProcessor(
+ /// "WeatherReport",
+ /// new WeatherReport.Processor(new WeatherReportHandler()));
+ ///
+ /// TServerTransport t = new TServerSocket(9090);
+ /// TSimpleServer server = new TSimpleServer(processor, t);
+ ///
+ /// server.serve();
+ /// </code>
+ /// </summary>
+ public class TMultiplexedProcessor : TProcessor
+ {
+ private Dictionary<string, TProcessor> ServiceProcessorMap = new Dictionary<string, TProcessor>();
+
+ /// <summary>
+ /// 'Register' a service with this TMultiplexedProcessor. This allows us to broker
+ /// requests to individual services by using the service name to select them at request time.
+ ///
+ /// Args:
+ /// - serviceName Name of a service, has to be identical to the name
+ /// declared in the Thrift IDL, e.g. "WeatherReport".
+ /// - processor Implementation of a service, usually referred to as "handlers",
+ /// e.g. WeatherReportHandler implementing WeatherReport.Iface.
+ /// </summary>
+ public void RegisterProcessor(string serviceName, TProcessor processor)
+ {
+ ServiceProcessorMap.Add(serviceName, processor);
+ }
+
+
+ private void Fail(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, string etxt)
+ {
+ TApplicationException appex = new TApplicationException(extype, etxt);
+
+ TMessage newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID);
+
+ oprot.WriteMessageBegin(newMessage);
+ appex.Write(oprot);
+ oprot.WriteMessageEnd();
+ oprot.Transport.Flush();
+ }
+
+
+ /// <summary>
+ /// This implementation of process performs the following steps:
+ ///
+ /// - Read the beginning of the message.
+ /// - Extract the service name from the message.
+ /// - Using the service name to locate the appropriate processor.
+ /// - Dispatch to the processor, with a decorated instance of TProtocol
+ /// that allows readMessageBegin() to return the original TMessage.
+ /// <para/>
+ /// Throws an exception if
+ /// - the message type is not CALL or ONEWAY,
+ /// - the service name was not found in the message, or
+ /// - the service name has not been RegisterProcessor()ed.
+ /// </summary>
+ public bool Process(TProtocol iprot, TProtocol oprot)
+ {
+ /* Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+ message header. This pulls the message "off the wire", which we'll
+ deal with at the end of this method. */
+
+ try
+ {
+ TMessage message = iprot.ReadMessageBegin();
+
+ if ((message.Type != TMessageType.Call) && (message.Type != TMessageType.Oneway))
+ {
+ Fail(oprot, message,
+ TApplicationException.ExceptionType.InvalidMessageType,
+ "Message type CALL or ONEWAY expected");
+ return false;
+ }
+
+ // Extract the service name
+ int index = message.Name.IndexOf(TMultiplexedProtocol.SEPARATOR);
+ if (index < 0)
+ {
+ Fail(oprot, message,
+ TApplicationException.ExceptionType.InvalidProtocol,
+ "Service name not found in message name: " + message.Name + ". " +
+ "Did you forget to use a TMultiplexProtocol in your client?");
+ return false;
+ }
+
+ // Create a new TMessage, something that can be consumed by any TProtocol
+ string serviceName = message.Name.Substring(0, index);
+ TProcessor actualProcessor;
+ if (!ServiceProcessorMap.TryGetValue(serviceName, out actualProcessor))
+ {
+ Fail(oprot, message,
+ TApplicationException.ExceptionType.InternalError,
+ "Service name not found: " + serviceName + ". " +
+ "Did you forget to call RegisterProcessor()?");
+ return false;
+ }
+
+ // Create a new TMessage, removing the service name
+ TMessage newMessage = new TMessage(
+ message.Name.Substring(serviceName.Length + TMultiplexedProtocol.SEPARATOR.Length),
+ message.Type,
+ message.SeqID);
+
+ // Dispatch processing to the stored processor
+ return actualProcessor.Process(new StoredMessageProtocol(iprot, newMessage), oprot);
+
+ }
+ catch (IOException)
+ {
+ return false; // similar to all other processors
+ }
+
+ }
+
+ /// <summary>
+ /// Our goal was to work with any protocol. In order to do that, we needed
+ /// to allow them to call readMessageBegin() and get a TMessage in exactly
+ /// the standard format, without the service name prepended to TMessage.name.
+ /// </summary>
+ private class StoredMessageProtocol : TProtocolDecorator
+ {
+ TMessage MsgBegin;
+
+ public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin)
+ : base(protocol)
+ {
+ this.MsgBegin = messageBegin;
+ }
+
+ public override TMessage ReadMessageBegin()
+ {
+ return MsgBegin;
+ }
+ }
+
+ }
+}
diff --git a/lib/csharp/src/Protocol/TMultiplexedProtocol.cs b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
new file mode 100644
index 0000000..1bd420f
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+
+ /// <summary>
+ /// TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
+ /// client to communicate with a multiplexing Thrift server, by prepending the service name
+ /// to the function name during function calls.
+ /// <para/>
+ /// NOTE: THIS IS NOT TO BE USED BY SERVERS.
+ /// On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+ /// <para/>
+ /// This example uses a single socket transport to invoke two services:
+ /// <code>
+ /// TSocket transport = new TSocket("localhost", 9090);
+ /// transport.open();
+ ///
+ /// TBinaryProtocol protocol = new TBinaryProtocol(transport);
+ ///
+ /// TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+ /// Calculator.Client service = new Calculator.Client(mp);
+ ///
+ /// TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+ /// WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+ ///
+ /// System.out.println(service.add(2,2));
+ /// System.out.println(service2.getTemperature());
+ /// </code>
+ /// </summary>
+ public class TMultiplexedProtocol : TProtocolDecorator
+ {
+
+ /// <summary>
+ /// Used to delimit the service name from the function name.
+ /// </summary>
+ public static string SEPARATOR = ":";
+
+ private string ServiceName;
+
+ /// <summary>
+ /// Wrap the specified protocol, allowing it to be used to communicate with a
+ /// multiplexing server. The <paramref name="serviceName"/> is required as it is
+ /// prepended to the message header so that the multiplexing server can broker
+ /// the function call to the proper service.
+ /// </summary>
+ /// <param name="protocol">Your communication protocol of choice, e.g. <see cref="TBinaryProtocol"/>.</param>
+ /// <param name="serviceName">The service name of the service communicating via this protocol.</param>
+ public TMultiplexedProtocol(TProtocol protocol, string serviceName)
+ : base(protocol)
+ {
+ ServiceName = serviceName;
+ }
+
+ /// <summary>
+ /// Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+ /// </summary>
+ /// <param name="tMessage">The original message.</param>
+ public override void WriteMessageBegin(TMessage tMessage)
+ {
+ switch (tMessage.Type)
+ {
+ case TMessageType.Call:
+ case TMessageType.Oneway:
+ base.WriteMessageBegin(new TMessage(
+ ServiceName + SEPARATOR + tMessage.Name,
+ tMessage.Type,
+ tMessage.SeqID));
+ break;
+
+ default:
+ base.WriteMessageBegin(tMessage);
+ break;
+ }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs
new file mode 100644
index 0000000..dd7a6e0
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocol.cs
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+ public abstract class TProtocol : IDisposable
+ {
+ private const int DEFAULT_RECURSION_DEPTH = 64;
+
+ protected TTransport trans;
+ protected int recursionLimit;
+ protected int recursionDepth;
+
+ protected TProtocol(TTransport trans)
+ {
+ this.trans = trans;
+ this.recursionLimit = DEFAULT_RECURSION_DEPTH;
+ this.recursionDepth = 0;
+ }
+
+ public TTransport Transport
+ {
+ get { return trans; }
+ }
+
+ public int RecursionLimit
+ {
+ get { return recursionLimit; }
+ set { recursionLimit = value; }
+ }
+
+ public void IncrementRecursionDepth()
+ {
+ if (recursionDepth < recursionLimit)
+ ++recursionDepth;
+ else
+ throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+ }
+
+ public void DecrementRecursionDepth()
+ {
+ --recursionDepth;
+ }
+
+ #region " IDisposable Support "
+ private bool _IsDisposed;
+
+ // IDisposable
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_IsDisposed)
+ {
+ if (disposing)
+ {
+ if (trans is IDisposable)
+ (trans as IDisposable).Dispose();
+ }
+ }
+ _IsDisposed = true;
+ }
+ #endregion
+
+ 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(sbyte 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 virtual void WriteString(string s)
+ {
+ WriteBinary(Encoding.UTF8.GetBytes(s));
+ }
+ public abstract void WriteBinary(byte[] b);
+
+ 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 sbyte ReadByte();
+ public abstract short ReadI16();
+ public abstract int ReadI32();
+ public abstract long ReadI64();
+ public abstract double ReadDouble();
+ public virtual string ReadString()
+ {
+ var buf = ReadBinary();
+ return Encoding.UTF8.GetString(buf, 0, buf.Length);
+ }
+ public abstract byte[] ReadBinary();
+ }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolDecorator.cs b/lib/csharp/src/Protocol/TProtocolDecorator.cs
new file mode 100644
index 0000000..8600002
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolDecorator.cs
@@ -0,0 +1,261 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+ /// <summary>
+ /// <see cref="TProtocolDecorator"/> forwards all requests to an enclosed <see cref="TProtocol"/> instance,
+ /// providing a way to author concise concrete decorator subclasses. While it has
+ /// no abstract methods, it is marked abstract as a reminder that by itself,
+ /// it does not modify the behaviour of the enclosed <see cref="TProtocol"/>.
+ /// <para/>
+ /// See p.175 of Design Patterns (by Gamma et al.)
+ /// </summary>
+ /// <seealso cref="TMultiplexedProtocol"/>
+ public abstract class TProtocolDecorator : TProtocol
+ {
+ private TProtocol WrappedProtocol;
+
+ /// <summary>
+ /// Encloses the specified protocol.
+ /// </summary>
+ /// <param name="protocol">All operations will be forward to this protocol. Must be non-null.</param>
+ public TProtocolDecorator(TProtocol protocol)
+ : base(protocol.Transport)
+ {
+
+ WrappedProtocol = protocol;
+ }
+
+ public override void WriteMessageBegin(TMessage tMessage)
+ {
+ WrappedProtocol.WriteMessageBegin(tMessage);
+ }
+
+ public override void WriteMessageEnd()
+ {
+ WrappedProtocol.WriteMessageEnd();
+ }
+
+ public override void WriteStructBegin(TStruct tStruct)
+ {
+ WrappedProtocol.WriteStructBegin(tStruct);
+ }
+
+ public override void WriteStructEnd()
+ {
+ WrappedProtocol.WriteStructEnd();
+ }
+
+ public override void WriteFieldBegin(TField tField)
+ {
+ WrappedProtocol.WriteFieldBegin(tField);
+ }
+
+ public override void WriteFieldEnd()
+ {
+ WrappedProtocol.WriteFieldEnd();
+ }
+
+ public override void WriteFieldStop()
+ {
+ WrappedProtocol.WriteFieldStop();
+ }
+
+ public override void WriteMapBegin(TMap tMap)
+ {
+ WrappedProtocol.WriteMapBegin(tMap);
+ }
+
+ public override void WriteMapEnd()
+ {
+ WrappedProtocol.WriteMapEnd();
+ }
+
+ public override void WriteListBegin(TList tList)
+ {
+ WrappedProtocol.WriteListBegin(tList);
+ }
+
+ public override void WriteListEnd()
+ {
+ WrappedProtocol.WriteListEnd();
+ }
+
+ public override void WriteSetBegin(TSet tSet)
+ {
+ WrappedProtocol.WriteSetBegin(tSet);
+ }
+
+ public override void WriteSetEnd()
+ {
+ WrappedProtocol.WriteSetEnd();
+ }
+
+ public override void WriteBool(bool b)
+ {
+ WrappedProtocol.WriteBool(b);
+ }
+
+ public override void WriteByte(sbyte b)
+ {
+ WrappedProtocol.WriteByte(b);
+ }
+
+ public override void WriteI16(short i)
+ {
+ WrappedProtocol.WriteI16(i);
+ }
+
+ public override void WriteI32(int i)
+ {
+ WrappedProtocol.WriteI32(i);
+ }
+
+ public override void WriteI64(long l)
+ {
+ WrappedProtocol.WriteI64(l);
+ }
+
+ public override void WriteDouble(double v)
+ {
+ WrappedProtocol.WriteDouble(v);
+ }
+
+ public override void WriteString(string s)
+ {
+ WrappedProtocol.WriteString(s);
+ }
+
+ public override void WriteBinary(byte[] bytes)
+ {
+ WrappedProtocol.WriteBinary(bytes);
+ }
+
+ public override TMessage ReadMessageBegin()
+ {
+ return WrappedProtocol.ReadMessageBegin();
+ }
+
+ public override void ReadMessageEnd()
+ {
+ WrappedProtocol.ReadMessageEnd();
+ }
+
+ public override TStruct ReadStructBegin()
+ {
+ return WrappedProtocol.ReadStructBegin();
+ }
+
+ public override void ReadStructEnd()
+ {
+ WrappedProtocol.ReadStructEnd();
+ }
+
+ public override TField ReadFieldBegin()
+ {
+ return WrappedProtocol.ReadFieldBegin();
+ }
+
+ public override void ReadFieldEnd()
+ {
+ WrappedProtocol.ReadFieldEnd();
+ }
+
+ public override TMap ReadMapBegin()
+ {
+ return WrappedProtocol.ReadMapBegin();
+ }
+
+ public override void ReadMapEnd()
+ {
+ WrappedProtocol.ReadMapEnd();
+ }
+
+ public override TList ReadListBegin()
+ {
+ return WrappedProtocol.ReadListBegin();
+ }
+
+ public override void ReadListEnd()
+ {
+ WrappedProtocol.ReadListEnd();
+ }
+
+ public override TSet ReadSetBegin()
+ {
+ return WrappedProtocol.ReadSetBegin();
+ }
+
+ public override void ReadSetEnd()
+ {
+ WrappedProtocol.ReadSetEnd();
+ }
+
+ public override bool ReadBool()
+ {
+ return WrappedProtocol.ReadBool();
+ }
+
+ public override sbyte ReadByte()
+ {
+ return WrappedProtocol.ReadByte();
+ }
+
+ public override short ReadI16()
+ {
+ return WrappedProtocol.ReadI16();
+ }
+
+ public override int ReadI32()
+ {
+ return WrappedProtocol.ReadI32();
+ }
+
+ public override long ReadI64()
+ {
+ return WrappedProtocol.ReadI64();
+ }
+
+ public override double ReadDouble()
+ {
+ return WrappedProtocol.ReadDouble();
+ }
+
+ public override string ReadString()
+ {
+ return WrappedProtocol.ReadString();
+ }
+
+ public override byte[] ReadBinary()
+ {
+ return WrappedProtocol.ReadBinary();
+ }
+ }
+
+}
diff --git a/lib/csharp/src/Protocol/TProtocolException.cs b/lib/csharp/src/Protocol/TProtocolException.cs
new file mode 100644
index 0000000..7bef236
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolException.cs
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+ public class TProtocolException : TException
+ {
+ 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;
+ public const int NOT_IMPLEMENTED = 5;
+ public const int DEPTH_LIMIT = 6;
+
+ protected int type_ = UNKNOWN;
+
+ public TProtocolException()
+ : base()
+ {
+ }
+
+ public TProtocolException(int type, Exception inner = null)
+ : base(string.Empty, inner)
+ {
+ type_ = type;
+ }
+
+ public TProtocolException(int type, string message, Exception inner = null)
+ : base(message, inner)
+ {
+ type_ = type;
+ }
+
+ public TProtocolException(string message, Exception inner = null)
+ : base(message, inner)
+ {
+ }
+
+ 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
index 0000000..71360a1
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolFactory.cs
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+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
index 0000000..d995c6c
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolUtil.cs
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+ public static class TProtocolUtil
+ {
+ public static void Skip(TProtocol prot, TType type)
+ {
+ prot.IncrementRecursionDepth();
+ try
+ {
+ 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:
+ // Don't try to decode the string, just skip it.
+ prot.ReadBinary();
+ 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;
+ default:
+ throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
+ }
+ }
+ finally
+ {
+ prot.DecrementRecursionDepth();
+ }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TSet.cs b/lib/csharp/src/Protocol/TSet.cs
new file mode 100644
index 0000000..a918ab5
--- /dev/null
+++ b/lib/csharp/src/Protocol/TSet.cs
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TSet
+ {
+ private TType elementType;
+ private int count;
+
+ public TSet(TType elementType, int count)
+ :this()
+ {
+ this.elementType = elementType;
+ this.count = count;
+ }
+
+ public TSet(TList list)
+ : this(list.ElementType, list.Count)
+ {
+ }
+
+ public TType ElementType
+ {
+ get { return elementType; }
+ set { elementType = value; }
+ }
+
+ public int Count
+ {
+ get { return count; }
+ set { count = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TStruct.cs b/lib/csharp/src/Protocol/TStruct.cs
new file mode 100644
index 0000000..f4844a4
--- /dev/null
+++ b/lib/csharp/src/Protocol/TStruct.cs
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+ public struct TStruct
+ {
+ private string name;
+
+ public TStruct(string name)
+ :this()
+ {
+ this.name = name;
+ }
+
+ public string Name
+ {
+ get { return name; }
+ set { name = value; }
+ }
+ }
+}
diff --git a/lib/csharp/src/Protocol/TType.cs b/lib/csharp/src/Protocol/TType.cs
new file mode 100644
index 0000000..9ce915e
--- /dev/null
+++ b/lib/csharp/src/Protocol/TType.cs
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+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
index 0000000..2bc04f3
--- /dev/null
+++ b/lib/csharp/src/Server/TServer.cs
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+using Thrift.Transport;
+using System.IO;
+
+namespace Thrift.Server
+{
+ public abstract class TServer
+ {
+ //Attributes
+ protected TProcessorFactory processorFactory;
+ protected TServerTransport serverTransport;
+ protected TTransportFactory inputTransportFactory;
+ protected TTransportFactory outputTransportFactory;
+ protected TProtocolFactory inputProtocolFactory;
+ protected TProtocolFactory outputProtocolFactory;
+ protected TServerEventHandler serverEventHandler = null;
+
+ //Methods
+ public void setEventHandler(TServerEventHandler seh)
+ {
+ serverEventHandler = seh;
+ }
+ public TServerEventHandler getEventHandler()
+ {
+ return serverEventHandler;
+ }
+
+ //Log delegation
+ public delegate void LogDelegate(string str);
+ private LogDelegate _logDelegate;
+ protected LogDelegate logDelegate
+ {
+ get { return _logDelegate; }
+ set { _logDelegate = (value != null) ? value : DefaultLogDelegate; }
+ }
+ protected static void DefaultLogDelegate(string s)
+ {
+ Console.Error.WriteLine(s);
+ }
+
+ //Construction
+ public TServer(TProcessor processor,
+ TServerTransport serverTransport)
+ : this(processor, serverTransport,
+ new TTransportFactory(),
+ new TTransportFactory(),
+ new TBinaryProtocol.Factory(),
+ new TBinaryProtocol.Factory(),
+ DefaultLogDelegate)
+ {
+ }
+
+ public TServer(TProcessor processor,
+ TServerTransport serverTransport,
+ LogDelegate logDelegate)
+ : this(processor,
+ serverTransport,
+ new TTransportFactory(),
+ new TTransportFactory(),
+ new TBinaryProtocol.Factory(),
+ new TBinaryProtocol.Factory(),
+ logDelegate)
+ {
+ }
+
+ public TServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory)
+ : this(processor,
+ serverTransport,
+ transportFactory,
+ transportFactory,
+ new TBinaryProtocol.Factory(),
+ new TBinaryProtocol.Factory(),
+ DefaultLogDelegate)
+ {
+ }
+
+ public TServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : this(processor,
+ serverTransport,
+ transportFactory,
+ transportFactory,
+ protocolFactory,
+ protocolFactory,
+ DefaultLogDelegate)
+ {
+ }
+
+ public TServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory inputTransportFactory,
+ TTransportFactory outputTransportFactory,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ LogDelegate logDelegate)
+ {
+ this.processorFactory = new TSingletonProcessorFactory(processor);
+ this.serverTransport = serverTransport;
+ this.inputTransportFactory = inputTransportFactory;
+ this.outputTransportFactory = outputTransportFactory;
+ this.inputProtocolFactory = inputProtocolFactory;
+ this.outputProtocolFactory = outputProtocolFactory;
+ this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+ }
+
+ public TServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory inputTransportFactory,
+ TTransportFactory outputTransportFactory,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ LogDelegate logDelegate)
+ {
+ this.processorFactory = processorFactory;
+ this.serverTransport = serverTransport;
+ this.inputTransportFactory = inputTransportFactory;
+ this.outputTransportFactory = outputTransportFactory;
+ this.inputProtocolFactory = inputProtocolFactory;
+ this.outputProtocolFactory = outputProtocolFactory;
+ this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+ }
+
+ //Abstract Interface
+ public abstract void Serve();
+ public abstract void Stop();
+ }
+}
diff --git a/lib/csharp/src/Server/TServerEventHandler.cs b/lib/csharp/src/Server/TServerEventHandler.cs
new file mode 100644
index 0000000..e81efc6
--- /dev/null
+++ b/lib/csharp/src/Server/TServerEventHandler.cs
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Server
+{
+ /// <summary>
+ /// Interface implemented by server users to handle events from the server.
+ /// </summary>
+ public interface TServerEventHandler
+ {
+ /// <summary>
+ /// Called before the server begins.
+ /// </summary>
+ void preServe();
+
+ /// <summary>
+ /// Called when a new client has connected and is about to being processing.
+ /// </summary>
+ object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+ /// <summary>
+ /// Called when a client has finished request-handling to delete server context.
+ /// </summary>
+ void deleteContext(object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+ /// <summary>
+ /// Called when a client is about to call the processor.
+ /// </summary>
+ void processContext(object serverContext, Thrift.Transport.TTransport transport);
+ };
+}
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
new file mode 100644
index 0000000..4e7ea96
--- /dev/null
+++ b/lib/csharp/src/Server/TSimpleServer.cs
@@ -0,0 +1,180 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Transport;
+using Thrift.Protocol;
+
+namespace Thrift.Server
+{
+ /// <summary>
+ /// Simple single-threaded server for testing.
+ /// </summary>
+ public class TSimpleServer : TServer
+ {
+ private bool stop = false;
+
+ public TSimpleServer(TProcessor processor,
+ TServerTransport serverTransport)
+ : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
+ {
+ }
+
+ public TSimpleServer(TProcessor processor,
+ TServerTransport serverTransport,
+ LogDelegate logDel)
+ : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), logDel)
+ {
+ }
+
+ public TSimpleServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory)
+ : base(processor,
+ serverTransport,
+ transportFactory,
+ transportFactory,
+ new TBinaryProtocol.Factory(),
+ new TBinaryProtocol.Factory(),
+ DefaultLogDelegate)
+ {
+ }
+
+ public TSimpleServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : base(processor,
+ serverTransport,
+ transportFactory,
+ transportFactory,
+ protocolFactory,
+ protocolFactory,
+ DefaultLogDelegate)
+ {
+ }
+
+ public TSimpleServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : base(processorFactory,
+ serverTransport,
+ transportFactory,
+ transportFactory,
+ protocolFactory,
+ protocolFactory,
+ DefaultLogDelegate)
+ {
+ }
+
+ public override void Serve()
+ {
+ try
+ {
+ serverTransport.Listen();
+ }
+ catch (TTransportException ttx)
+ {
+ logDelegate(ttx.ToString());
+ return;
+ }
+
+ //Fire the preServe server event when server is up but before any client connections
+ if (serverEventHandler != null)
+ serverEventHandler.preServe();
+
+ while (!stop)
+ {
+ TProcessor processor = null;
+ TTransport client = null;
+ TTransport inputTransport = null;
+ TTransport outputTransport = null;
+ TProtocol inputProtocol = null;
+ TProtocol outputProtocol = null;
+ object connectionContext = null;
+ try
+ {
+ using (client = serverTransport.Accept())
+ {
+ processor = processorFactory.GetProcessor(client);
+ if (client != null)
+ {
+ using (inputTransport = inputTransportFactory.GetTransport(client))
+ {
+ using (outputTransport = outputTransportFactory.GetTransport(client))
+ {
+ inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+ outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+ //Recover event handler (if any) and fire createContext server event when a client connects
+ if (serverEventHandler != null)
+ connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+ //Process client requests until client disconnects
+ while (!stop)
+ {
+ if (!inputTransport.Peek())
+ break;
+
+ //Fire processContext server event
+ //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+ //That is to say it may be many minutes between the event firing and the client request
+ //actually arriving or the client may hang up without ever makeing a request.
+ if (serverEventHandler != null)
+ serverEventHandler.processContext(connectionContext, inputTransport);
+ //Process client request (blocks until transport is readable)
+ if (!processor.Process(inputProtocol, outputProtocol))
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (TTransportException ttx)
+ {
+ if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+ {
+ logDelegate(ttx.ToString());
+ }
+ }
+ catch (Exception x)
+ {
+ //Unexpected
+ logDelegate(x.ToString());
+ }
+
+ //Fire deleteContext server event after client disconnects
+ if (serverEventHandler != null)
+ serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+ }
+ }
+
+ public override void Stop()
+ {
+ stop = true;
+ serverTransport.Close();
+ }
+ }
+}
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
new file mode 100644
index 0000000..a494ce7
--- /dev/null
+++ b/lib/csharp/src/Server/TThreadPoolServer.cs
@@ -0,0 +1,295 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+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 = -1; // use .NET ThreadPool defaults
+ private const int DEFAULT_MAX_THREADS = -1; // use .NET ThreadPool defaults
+ private volatile bool stop = false;
+
+ public struct Configuration
+ {
+ public int MinWorkerThreads;
+ public int MaxWorkerThreads;
+ public int MinIOThreads;
+ public int MaxIOThreads;
+
+ public Configuration(int min = DEFAULT_MIN_THREADS, int max = DEFAULT_MAX_THREADS)
+ {
+ MinWorkerThreads = min;
+ MaxWorkerThreads = max;
+ MinIOThreads = min;
+ MaxIOThreads = max;
+ }
+
+ public Configuration(int minWork, int maxWork, int minIO, int maxIO)
+ {
+ MinWorkerThreads = minWork;
+ MaxWorkerThreads = maxWork;
+ MinIOThreads = minIO;
+ MaxIOThreads = maxIO;
+ }
+ }
+
+ public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ new TTransportFactory(), new TTransportFactory(),
+ new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+ new Configuration(), DefaultLogDelegate)
+ {
+ }
+
+ public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ new TTransportFactory(), new TTransportFactory(),
+ new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+ new Configuration(), logDelegate)
+ {
+ }
+
+ public TThreadPoolServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ transportFactory, transportFactory,
+ protocolFactory, protocolFactory,
+ new Configuration(), DefaultLogDelegate)
+ {
+ }
+
+ public TThreadPoolServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : this(processorFactory, serverTransport,
+ transportFactory, transportFactory,
+ protocolFactory, protocolFactory,
+ new Configuration(), DefaultLogDelegate)
+ {
+ }
+
+ public TThreadPoolServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory inputTransportFactory,
+ TTransportFactory outputTransportFactory,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
+ : this(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+ inputProtocolFactory, outputProtocolFactory,
+ new Configuration(minThreadPoolThreads, maxThreadPoolThreads),
+ logDel)
+ {
+ }
+
+ public TThreadPoolServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory inputTransportFactory,
+ TTransportFactory outputTransportFactory,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ Configuration threadConfig,
+ LogDelegate logDel)
+ : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+ inputProtocolFactory, outputProtocolFactory, logDel)
+ {
+ lock (typeof(TThreadPoolServer))
+ {
+ if ((threadConfig.MaxWorkerThreads > 0) || (threadConfig.MaxIOThreads > 0))
+ {
+ int work, comm;
+ ThreadPool.GetMaxThreads(out work, out comm);
+ if (threadConfig.MaxWorkerThreads > 0)
+ work = threadConfig.MaxWorkerThreads;
+ if (threadConfig.MaxIOThreads > 0)
+ comm = threadConfig.MaxIOThreads;
+ if (!ThreadPool.SetMaxThreads(work, comm))
+ throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+ }
+
+ if ((threadConfig.MinWorkerThreads > 0) || (threadConfig.MinIOThreads > 0))
+ {
+ int work, comm;
+ ThreadPool.GetMinThreads(out work, out comm);
+ if (threadConfig.MinWorkerThreads > 0)
+ work = threadConfig.MinWorkerThreads;
+ if (threadConfig.MinIOThreads > 0)
+ comm = threadConfig.MinIOThreads;
+ if (!ThreadPool.SetMinThreads(work, comm))
+ throw new Exception("Error: could not SetMinThreads in ThreadPool");
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Use new ThreadPool thread for each new client connection.
+ /// </summary>
+ public override void Serve()
+ {
+ try
+ {
+ serverTransport.Listen();
+ }
+ catch (TTransportException ttx)
+ {
+ logDelegate("Error, could not listen on ServerTransport: " + ttx);
+ return;
+ }
+
+ //Fire the preServe server event when server is up but before any client connections
+ if (serverEventHandler != null)
+ serverEventHandler.preServe();
+
+ while (!stop)
+ {
+ int failureCount = 0;
+ try
+ {
+ TTransport client = serverTransport.Accept();
+ ThreadPool.QueueUserWorkItem(this.Execute, client);
+ }
+ catch (TTransportException ttx)
+ {
+ if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+ {
+ ++failureCount;
+ logDelegate(ttx.ToString());
+ }
+
+ }
+ }
+
+ if (stop)
+ {
+ try
+ {
+ serverTransport.Close();
+ }
+ catch (TTransportException ttx)
+ {
+ logDelegate("TServerTransport failed on close: " + ttx.Message);
+ }
+ stop = false;
+ }
+ }
+
+ /// <summary>
+ /// Loops on processing a client forever
+ /// threadContext will be a TTransport instance
+ /// </summary>
+ /// <param name="threadContext"></param>
+ private void Execute(object threadContext)
+ {
+ using (TTransport client = (TTransport)threadContext)
+ {
+ TProcessor processor = processorFactory.GetProcessor(client, this);
+ TTransport inputTransport = null;
+ TTransport outputTransport = null;
+ TProtocol inputProtocol = null;
+ TProtocol outputProtocol = null;
+ object connectionContext = null;
+ try
+ {
+ try
+ {
+ inputTransport = inputTransportFactory.GetTransport(client);
+ outputTransport = outputTransportFactory.GetTransport(client);
+ inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+ outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+ //Recover event handler (if any) and fire createContext server event when a client connects
+ if (serverEventHandler != null)
+ connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+ //Process client requests until client disconnects
+ while (!stop)
+ {
+ if (!inputTransport.Peek())
+ break;
+
+ //Fire processContext server event
+ //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+ //That is to say it may be many minutes between the event firing and the client request
+ //actually arriving or the client may hang up without ever makeing a request.
+ if (serverEventHandler != null)
+ serverEventHandler.processContext(connectionContext, inputTransport);
+ //Process client request (blocks until transport is readable)
+ if (!processor.Process(inputProtocol, outputProtocol))
+ break;
+ }
+ }
+ catch (TTransportException)
+ {
+ //Usually a client disconnect, expected
+ }
+ catch (Exception x)
+ {
+ //Unexpected
+ logDelegate("Error: " + x);
+ }
+
+ //Fire deleteContext server event after client disconnects
+ if (serverEventHandler != null)
+ serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+ }
+ finally
+ {
+ //Close transports
+ if (inputTransport != null)
+ inputTransport.Close();
+ if (outputTransport != null)
+ outputTransport.Close();
+
+ // disposable stuff should be disposed
+ if (inputProtocol != null)
+ inputProtocol.Dispose();
+ if (outputProtocol != null)
+ outputProtocol.Dispose();
+ if (inputTransport != null)
+ inputTransport.Dispose();
+ if (outputTransport != null)
+ outputTransport.Dispose();
+ }
+ }
+ }
+
+ public override void Stop()
+ {
+ stop = true;
+ serverTransport.Close();
+ }
+ }
+}
diff --git a/lib/csharp/src/Server/TThreadedServer.cs b/lib/csharp/src/Server/TThreadedServer.cs
new file mode 100644
index 0000000..cc051a3
--- /dev/null
+++ b/lib/csharp/src/Server/TThreadedServer.cs
@@ -0,0 +1,282 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using Thrift.Collections;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace Thrift.Server
+{
+ /// <summary>
+ /// Server that uses C# threads (as opposed to the ThreadPool) when handling requests.
+ /// </summary>
+ public class TThreadedServer : TServer
+ {
+ private const int DEFAULT_MAX_THREADS = 100;
+ private volatile bool stop = false;
+ private readonly int maxThreads;
+
+ private Queue<TTransport> clientQueue;
+ private THashSet<Thread> clientThreads;
+ private object clientLock;
+ private Thread workerThread;
+
+ public int ClientThreadsCount
+ {
+ get { return clientThreads.Count; }
+ }
+
+ public TThreadedServer(TProcessor processor, TServerTransport serverTransport)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ new TTransportFactory(), new TTransportFactory(),
+ new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+ DEFAULT_MAX_THREADS, DefaultLogDelegate)
+ {
+ }
+
+ public TThreadedServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ new TTransportFactory(), new TTransportFactory(),
+ new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+ DEFAULT_MAX_THREADS, logDelegate)
+ {
+ }
+
+
+ public TThreadedServer(TProcessor processor,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : this(new TSingletonProcessorFactory(processor), serverTransport,
+ transportFactory, transportFactory,
+ protocolFactory, protocolFactory,
+ DEFAULT_MAX_THREADS, DefaultLogDelegate)
+ {
+ }
+
+ public TThreadedServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory transportFactory,
+ TProtocolFactory protocolFactory)
+ : this(processorFactory, serverTransport,
+ transportFactory, transportFactory,
+ protocolFactory, protocolFactory,
+ DEFAULT_MAX_THREADS, DefaultLogDelegate)
+ {
+ }
+ public TThreadedServer(TProcessorFactory processorFactory,
+ TServerTransport serverTransport,
+ TTransportFactory inputTransportFactory,
+ TTransportFactory outputTransportFactory,
+ TProtocolFactory inputProtocolFactory,
+ TProtocolFactory outputProtocolFactory,
+ int maxThreads, LogDelegate logDel)
+ : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+ inputProtocolFactory, outputProtocolFactory, logDel)
+ {
+ this.maxThreads = maxThreads;
+ clientQueue = new Queue<TTransport>();
+ clientLock = new object();
+ clientThreads = new THashSet<Thread>();
+ }
+
+ /// <summary>
+ /// Use new Thread for each new client connection. block until numConnections < maxThreads.
+ /// </summary>
+ public override void Serve()
+ {
+ try
+ {
+ //start worker thread
+ workerThread = new Thread(new ThreadStart(Execute));
+ workerThread.Start();
+ serverTransport.Listen();
+ }
+ catch (TTransportException ttx)
+ {
+ logDelegate("Error, could not listen on ServerTransport: " + ttx);
+ return;
+ }
+
+ //Fire the preServe server event when server is up but before any client connections
+ if (serverEventHandler != null)
+ serverEventHandler.preServe();
+
+ while (!stop)
+ {
+ int failureCount = 0;
+ try
+ {
+ TTransport client = serverTransport.Accept();
+ lock (clientLock)
+ {
+ clientQueue.Enqueue(client);
+ Monitor.Pulse(clientLock);
+ }
+ }
+ catch (TTransportException ttx)
+ {
+ if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+ {
+ ++failureCount;
+ logDelegate(ttx.ToString());
+ }
+
+ }
+ }
+
+ if (stop)
+ {
+ try
+ {
+ serverTransport.Close();
+ }
+ catch (TTransportException ttx)
+ {
+ logDelegate("TServeTransport failed on close: " + ttx.Message);
+ }
+ stop = false;
+ }
+ }
+
+ /// <summary>
+ /// Loops on processing a client forever
+ /// </summary>
+ private void Execute()
+ {
+ while (!stop)
+ {
+ TTransport client;
+ Thread t;
+ lock (clientLock)
+ {
+ //don't dequeue if too many connections
+ while (clientThreads.Count >= maxThreads)
+ {
+ Monitor.Wait(clientLock);
+ }
+
+ while (clientQueue.Count == 0)
+ {
+ Monitor.Wait(clientLock);
+ }
+
+ client = clientQueue.Dequeue();
+ t = new Thread(new ParameterizedThreadStart(ClientWorker));
+ clientThreads.Add(t);
+ }
+ //start processing requests from client on new thread
+ t.Start(client);
+ }
+ }
+
+ private void ClientWorker(object context)
+ {
+ using (TTransport client = (TTransport)context)
+ {
+ TProcessor processor = processorFactory.GetProcessor(client);
+ TTransport inputTransport = null;
+ TTransport outputTransport = null;
+ TProtocol inputProtocol = null;
+ TProtocol outputProtocol = null;
+ object connectionContext = null;
+ try
+ {
+ try
+ {
+ inputTransport = inputTransportFactory.GetTransport(client);
+ outputTransport = outputTransportFactory.GetTransport(client);
+ inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+ outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+ //Recover event handler (if any) and fire createContext server event when a client connects
+ if (serverEventHandler != null)
+ connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+ //Process client requests until client disconnects
+ while (!stop)
+ {
+ if (!inputTransport.Peek())
+ break;
+
+ //Fire processContext server event
+ //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+ //That is to say it may be many minutes between the event firing and the client request
+ //actually arriving or the client may hang up without ever makeing a request.
+ if (serverEventHandler != null)
+ serverEventHandler.processContext(connectionContext, inputTransport);
+ //Process client request (blocks until transport is readable)
+ if (!processor.Process(inputProtocol, outputProtocol))
+ break;
+ }
+ }
+ catch (TTransportException)
+ {
+ //Usually a client disconnect, expected
+ }
+ catch (Exception x)
+ {
+ //Unexpected
+ logDelegate("Error: " + x);
+ }
+
+ //Fire deleteContext server event after client disconnects
+ if (serverEventHandler != null)
+ serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+ lock (clientLock)
+ {
+ clientThreads.Remove(Thread.CurrentThread);
+ Monitor.Pulse(clientLock);
+ }
+
+ }
+ finally
+ {
+ //Close transports
+ if (inputTransport != null)
+ inputTransport.Close();
+ if (outputTransport != null)
+ outputTransport.Close();
+
+ // disposable stuff should be disposed
+ if (inputProtocol != null)
+ inputProtocol.Dispose();
+ if (outputProtocol != null)
+ outputProtocol.Dispose();
+ }
+ }
+ }
+
+ public override void Stop()
+ {
+ stop = true;
+ serverTransport.Close();
+ //clean up all the threads myself
+ workerThread.Abort();
+ foreach (Thread t in clientThreads)
+ {
+ t.Abort();
+ }
+ }
+ }
+}
diff --git a/lib/csharp/src/TApplicationException.cs b/lib/csharp/src/TApplicationException.cs
new file mode 100644
index 0000000..8dd7ae5
--- /dev/null
+++ b/lib/csharp/src/TApplicationException.cs
@@ -0,0 +1,146 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+ public class TApplicationException : TException
+ {
+ protected ExceptionType type;
+
+ public TApplicationException()
+ {
+ }
+
+ public TApplicationException(ExceptionType type)
+ {
+ this.type = type;
+ }
+
+ public TApplicationException(ExceptionType type, string message)
+ : base(message, null) // TApplicationException is serializable, but we never serialize InnerException
+ {
+ this.type = type;
+ }
+
+ public static TApplicationException Read(TProtocol iprot)
+ {
+ TField field;
+
+ string message = null;
+ ExceptionType type = ExceptionType.Unknown;
+
+ iprot.ReadStructBegin();
+ 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,
+ InternalError,
+ ProtocolError,
+ InvalidTransform,
+ InvalidProtocol,
+ UnsupportedClientType
+ }
+
+ public ExceptionType Type
+ {
+ get { return type; }
+ }
+ }
+}
diff --git a/lib/csharp/src/TAsyncProcessor.cs b/lib/csharp/src/TAsyncProcessor.cs
new file mode 100644
index 0000000..ab43225
--- /dev/null
+++ b/lib/csharp/src/TAsyncProcessor.cs
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System.Threading.Tasks;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+ /// <summary>
+ /// Processes a message asynchronously.
+ /// </summary>
+ public interface TAsyncProcessor
+ {
+ /// <summary>
+ /// Processes the next part of the message.
+ /// </summary>
+ /// <param name="iprot">The input protocol.</param>
+ /// <param name="oprot">The output protocol.</param>
+ /// <returns>true if there's more to process, false otherwise.</returns>
+ Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot);
+ }
+}
diff --git a/lib/csharp/src/TControllingHandler.cs b/lib/csharp/src/TControllingHandler.cs
new file mode 100644
index 0000000..7b5203a
--- /dev/null
+++ b/lib/csharp/src/TControllingHandler.cs
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using Thrift.Server;
+
+namespace Thrift
+{
+ public interface TControllingHandler
+ {
+ TServer server { get; set; }
+ }
+}
diff --git a/lib/csharp/src/TException.cs b/lib/csharp/src/TException.cs
new file mode 100644
index 0000000..b9fae6e
--- /dev/null
+++ b/lib/csharp/src/TException.cs
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift
+{
+ public class TException : Exception
+ {
+ public TException()
+ {
+ }
+
+ public TException(string message, Exception inner = null)
+ : base(message, inner)
+ {
+ }
+
+ }
+}
diff --git a/lib/csharp/src/TProcessor.cs b/lib/csharp/src/TProcessor.cs
new file mode 100644
index 0000000..71ce755
--- /dev/null
+++ b/lib/csharp/src/TProcessor.cs
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+ public interface TProcessor
+ {
+ bool Process(TProtocol iprot, TProtocol oprot);
+ }
+}
diff --git a/lib/csharp/src/TProcessorFactory.cs b/lib/csharp/src/TProcessorFactory.cs
new file mode 100644
index 0000000..fdf631b
--- /dev/null
+++ b/lib/csharp/src/TProcessorFactory.cs
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+ public interface TProcessorFactory
+ {
+ TProcessor GetProcessor(TTransport trans, TServer server = null);
+ }
+}
diff --git a/lib/csharp/src/TPrototypeProcessorFactory.cs b/lib/csharp/src/TPrototypeProcessorFactory.cs
new file mode 100644
index 0000000..0b47261
--- /dev/null
+++ b/lib/csharp/src/TPrototypeProcessorFactory.cs
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+ public class TPrototypeProcessorFactory<P, H> : TProcessorFactory where P : TProcessor
+ {
+ object[] handlerArgs = null;
+
+ public TPrototypeProcessorFactory()
+ {
+ handlerArgs = new object[0];
+ }
+
+ public TPrototypeProcessorFactory(params object[] handlerArgs)
+ {
+ this.handlerArgs = handlerArgs;
+ }
+
+ public TProcessor GetProcessor(TTransport trans, TServer server = null)
+ {
+ H handler = (H)Activator.CreateInstance(typeof(H), handlerArgs);
+
+ TControllingHandler handlerServerRef = handler as TControllingHandler;
+ if (handlerServerRef != null)
+ {
+ handlerServerRef.server = server;
+ }
+ return Activator.CreateInstance(typeof(P), new object[] { handler }) as TProcessor;
+ }
+ }
+}
diff --git a/lib/csharp/src/TSingletonProcessorFactory.cs b/lib/csharp/src/TSingletonProcessorFactory.cs
new file mode 100644
index 0000000..ed2897b
--- /dev/null
+++ b/lib/csharp/src/TSingletonProcessorFactory.cs
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+ public class TSingletonProcessorFactory : TProcessorFactory
+ {
+ private readonly TProcessor processor_;
+
+ public TSingletonProcessorFactory(TProcessor processor)
+ {
+ processor_ = processor;
+ }
+
+ public TProcessor GetProcessor(TTransport trans, TServer server = null)
+ {
+ return processor_;
+ }
+ }
+}
diff --git a/lib/csharp/src/Thrift.45.csproj b/lib/csharp/src/Thrift.45.csproj
new file mode 100644
index 0000000..146e7f8
--- /dev/null
+++ b/lib/csharp/src/Thrift.45.csproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{EBCE35DA-CF6A-42BC-A357-A9C09B534299}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Thrift</RootNamespace>
+ <AssemblyName>Thrift45</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>portable</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>portable</DebugType>
... 8548 lines suppressed ...