@@ -1,6 +1,6 @@ | |||
{ | |||
"projects": [ "src" ], | |||
"sdk": { | |||
"version": "1.0.0-rc1-update1" | |||
} | |||
"sdk": { | |||
"version": "1.0.0-preview1-002702" | |||
} | |||
} |
@@ -4,12 +4,12 @@ | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>dff7afe3-ca77-4109-bade-b4b49a4f6648</ProjectGuid> | |||
<RootNamespace>Discord.Audio</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
@@ -17,5 +17,5 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -120,7 +120,7 @@ namespace Discord.Net.WebSockets | |||
SendIdentify(_userId.Value, _sessionId); | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
tasks.Add(WatcherAsync()); | |||
#endif | |||
tasks.AddRange(_engine.GetTasks(CancelToken)); | |||
@@ -178,7 +178,7 @@ namespace Discord.Net.WebSockets | |||
await Task.Delay(1).ConfigureAwait(false); | |||
if (_udp.Available > 0) | |||
{ | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
packet = _udp.Receive(ref endpoint); | |||
#else | |||
//TODO: Is this really the only way to end a Receive call in DOTNET5_4? | |||
@@ -346,7 +346,7 @@ namespace Discord.Net.WebSockets | |||
{ | |||
try | |||
{ | |||
_udp.Send(voicePacket, rtpPacketLength); | |||
await _udp.SendAsync(voicePacket, rtpPacketLength, _endpoint).ConfigureAwait(false); | |||
} | |||
catch (SocketException ex) | |||
{ | |||
@@ -371,7 +371,7 @@ namespace Discord.Net.WebSockets | |||
break; | |||
} | |||
} | |||
await _udp.SendAsync(pingPacket, pingPacket.Length).ConfigureAwait(false); | |||
await _udp.SendAsync(pingPacket, pingPacket.Length, _endpoint).ConfigureAwait(false); | |||
nextPingTicks = currentTicks + 5 * ticksPerSeconds; | |||
} | |||
} | |||
@@ -391,7 +391,7 @@ namespace Discord.Net.WebSockets | |||
catch (OperationCanceledException) { } | |||
catch (InvalidOperationException) { } //Includes ObjectDisposedException | |||
} | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken | |||
private async Task WatcherAsync() | |||
{ | |||
@@ -437,7 +437,6 @@ namespace Discord.Net.WebSockets | |||
_encryptionMode = UnencryptedMode; | |||
_isEncrypted = false; | |||
} | |||
_udp.Connect(_endpoint); | |||
_sequence = 0;// (ushort)_rand.Next(0, ushort.MaxValue); | |||
//No thread issue here because SendAsync doesn't start until _isReady is true | |||
@@ -446,7 +445,7 @@ namespace Discord.Net.WebSockets | |||
packet[1] = (byte)(_ssrc >> 16); | |||
packet[2] = (byte)(_ssrc >> 8); | |||
packet[3] = (byte)(_ssrc >> 0); | |||
await _udp.SendAsync(packet, 70).ConfigureAwait(false); | |||
await _udp.SendAsync(packet, 70, _endpoint).ConfigureAwait(false); | |||
} | |||
} | |||
break; | |||
@@ -2,26 +2,36 @@ | |||
"version": "0.9.1", | |||
"description": "A Discord.Net extension adding voice support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
"packOptions": { | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
}, | |||
"contentFiles": [ "libsodium.dll", "opus.dll" ] | |||
}, | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"contentFiles": [ "libsodium.dll", "opus.dll" ], | |||
"compilationOptions": { | |||
"buildOptions": { | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"preserveCompilationContext": true, | |||
"allowUnsafe": true, | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"NETStandard.Library": "1.5.0-rc2-24027", | |||
"Discord.Net": "0.9.1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
"netstandard1.3": { | |||
"imports": [ | |||
"dotnet5.4", | |||
"dnxcore50", | |||
"portable-net45+win8" | |||
] | |||
} | |||
} | |||
} |
@@ -4,12 +4,12 @@ | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>19793545-ef89-48f4-8100-3ebaad0a9141</ProjectGuid> | |||
<RootNamespace>Discord.Commands</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
@@ -17,5 +17,5 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -2,24 +2,34 @@ | |||
"version": "0.9.1", | |||
"description": "A Discord.Net extension adding basic command support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
"packOptions": { | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
} | |||
}, | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"compilationOptions": { | |||
"buildOptions": { | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"preserveCompilationContext": true, | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"NETStandard.Library": "1.5.0-rc2-24027", | |||
"Discord.Net": "0.9.1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
"netstandard1.3": { | |||
"imports": [ | |||
"dotnet5.4", | |||
"dnxcore50", | |||
"portable-net45+win8" | |||
] | |||
} | |||
} | |||
} |
@@ -4,12 +4,12 @@ | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>01584e8a-78da-486f-9ef9-a894e435841b</ProjectGuid> | |||
<RootNamespace>Discord.Modules</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
@@ -17,5 +17,5 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -2,25 +2,35 @@ | |||
"version": "0.9.1", | |||
"description": "A Discord.Net extension adding basic plugin support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
"packOptions": { | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
} | |||
}, | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"compilationOptions": { | |||
"buildOptions": { | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"preserveCompilationContext": true, | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"NETStandard.Library": "1.5.0-rc2-24027", | |||
"Discord.Net": "0.9.1", | |||
"Discord.Net.Commands": "0.9.1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dotnet5.4": { } | |||
"netstandard1.3": { | |||
"imports": [ | |||
"dotnet5.4", | |||
"dnxcore50", | |||
"portable-net45+win8" | |||
] | |||
} | |||
} | |||
} |
@@ -550,9 +550,6 @@ | |||
<Compile Include="..\Discord.Net\Net\Rest\CompletedRequestEventArgs.cs"> | |||
<Link>Net\Rest\CompletedRequestEventArgs.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\Rest\ETFRestClient.cs"> | |||
<Link>Net\Rest\ETFRestClient.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Net\Rest\IRestEngine.cs"> | |||
<Link>Net\Rest\IRestEngine.cs</Link> | |||
</Compile> | |||
@@ -4,12 +4,12 @@ | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>acfb060b-ec8a-4926-b293-04c01e17ee23</ProjectGuid> | |||
<RootNamespace>Discord</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
@@ -17,5 +17,5 @@ | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -243,12 +243,15 @@ namespace Discord | |||
} | |||
ClientAPI.Token = token; | |||
var request = new LoginRequest() { Email = email, Password = password }; | |||
var response = await ClientAPI.Send(request).ConfigureAwait(false); | |||
token = response.Token; | |||
if (Config.CacheDir != null && token != oldToken && tokenPath != null) | |||
SaveToken(tokenPath, cacheKey, token); | |||
ClientAPI.Token = token; | |||
if (email != null && password != null) | |||
{ | |||
var request = new LoginRequest() { Email = email, Password = password }; | |||
var response = await ClientAPI.Send(request).ConfigureAwait(false); | |||
token = response.Token; | |||
if (Config.CacheDir != null && token != oldToken && tokenPath != null) | |||
SaveToken(tokenPath, cacheKey, token); | |||
ClientAPI.Token = token; | |||
} | |||
//Cache other stuff | |||
var regionsResponse = (await ClientAPI.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false)); | |||
@@ -1,491 +1,491 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Reflection; | |||
using System.Reflection.Emit; | |||
using System.Text; | |||
//using Newtonsoft.Json; | |||
//using System; | |||
//using System.Collections.Concurrent; | |||
//using System.Collections.Generic; | |||
//using System.IO; | |||
//using System.Linq; | |||
//using System.Reflection; | |||
//using System.Reflection.Emit; | |||
//using System.Text; | |||
namespace Discord.ETF | |||
{ | |||
public class ETFReader : IDisposable | |||
{ | |||
private static readonly ConcurrentDictionary<Type, Delegate> _deserializers = new ConcurrentDictionary<Type, Delegate>(); | |||
private static readonly Dictionary<Type, MethodInfo> _readMethods = GetPrimitiveReadMethods(); | |||
//namespace Discord.ETF | |||
//{ | |||
// public class ETFReader : IDisposable | |||
// { | |||
// private static readonly ConcurrentDictionary<Type, Delegate> _deserializers = new ConcurrentDictionary<Type, Delegate>(); | |||
// private static readonly Dictionary<Type, MethodInfo> _readMethods = GetPrimitiveReadMethods(); | |||
private readonly Stream _stream; | |||
private readonly byte[] _buffer; | |||
private readonly bool _leaveOpen; | |||
private readonly Encoding _encoding; | |||
// private readonly Stream _stream; | |||
// private readonly byte[] _buffer; | |||
// private readonly bool _leaveOpen; | |||
// private readonly Encoding _encoding; | |||
public ETFReader(Stream stream, bool leaveOpen = false) | |||
{ | |||
if (stream == null) throw new ArgumentNullException(nameof(stream)); | |||
// public ETFReader(Stream stream, bool leaveOpen = false) | |||
// { | |||
// if (stream == null) throw new ArgumentNullException(nameof(stream)); | |||
_stream = stream; | |||
_leaveOpen = leaveOpen; | |||
_buffer = new byte[11]; | |||
_encoding = Encoding.UTF8; | |||
} | |||
// _stream = stream; | |||
// _leaveOpen = leaveOpen; | |||
// _buffer = new byte[11]; | |||
// _encoding = Encoding.UTF8; | |||
// } | |||
public bool ReadBool() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT) | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
switch (_buffer[0]) //Length | |||
{ | |||
case 4: | |||
ReadTrue(); | |||
return true; | |||
case 5: | |||
ReadFalse(); | |||
return false; | |||
} | |||
} | |||
throw new InvalidDataException(); | |||
} | |||
private void ReadTrue() | |||
{ | |||
_stream.Read(_buffer, 0, 4); | |||
if (_buffer[0] != 't' || _buffer[1] != 'r' || _buffer[2] != 'u' || _buffer[3] != 'e') | |||
throw new InvalidDataException(); | |||
} | |||
private void ReadFalse() | |||
{ | |||
_stream.Read(_buffer, 0, 5); | |||
if (_buffer[0] != 'f' || _buffer[1] != 'a' || _buffer[2] != 'l' || _buffer[3] != 's' || _buffer[4] != 'e') | |||
throw new InvalidDataException(); | |||
} | |||
// public bool ReadBool() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT) | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// switch (_buffer[0]) //Length | |||
// { | |||
// case 4: | |||
// ReadTrue(); | |||
// return true; | |||
// case 5: | |||
// ReadFalse(); | |||
// return false; | |||
// } | |||
// } | |||
// throw new InvalidDataException(); | |||
// } | |||
// private void ReadTrue() | |||
// { | |||
// _stream.Read(_buffer, 0, 4); | |||
// if (_buffer[0] != 't' || _buffer[1] != 'r' || _buffer[2] != 'u' || _buffer[3] != 'e') | |||
// throw new InvalidDataException(); | |||
// } | |||
// private void ReadFalse() | |||
// { | |||
// _stream.Read(_buffer, 0, 5); | |||
// if (_buffer[0] != 'f' || _buffer[1] != 'a' || _buffer[2] != 'l' || _buffer[3] != 's' || _buffer[4] != 'e') | |||
// throw new InvalidDataException(); | |||
// } | |||
public int ReadSByte() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (sbyte)ReadLongInternal(type); | |||
} | |||
public uint ReadByte() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (byte)ReadLongInternal(type); | |||
} | |||
public int ReadShort() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (short)ReadLongInternal(type); | |||
} | |||
public uint ReadUShort() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (ushort)ReadLongInternal(type); | |||
} | |||
public int ReadInt() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (int)ReadLongInternal(type); | |||
} | |||
public uint ReadUInt() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (uint)ReadLongInternal(type); | |||
} | |||
public long ReadLong() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return ReadLongInternal(type); | |||
} | |||
public ulong ReadULong() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (ulong)ReadLongInternal(type); | |||
} | |||
public long ReadLongInternal(ETFType type) | |||
{ | |||
switch (type) | |||
{ | |||
case ETFType.SMALL_INTEGER_EXT: | |||
_stream.Read(_buffer, 0, 1); | |||
return _buffer[0]; | |||
case ETFType.INTEGER_EXT: | |||
_stream.Read(_buffer, 0, 4); | |||
return (_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | (_buffer[3]); | |||
case ETFType.SMALL_BIG_EXT: | |||
_stream.Read(_buffer, 0, 2); | |||
bool isPositive = _buffer[0] == 0; | |||
byte count = _buffer[1]; | |||
// public int ReadSByte() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (sbyte)ReadLongInternal(type); | |||
// } | |||
// public uint ReadByte() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (byte)ReadLongInternal(type); | |||
// } | |||
// public int ReadShort() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (short)ReadLongInternal(type); | |||
// } | |||
// public uint ReadUShort() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (ushort)ReadLongInternal(type); | |||
// } | |||
// public int ReadInt() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (int)ReadLongInternal(type); | |||
// } | |||
// public uint ReadUInt() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (uint)ReadLongInternal(type); | |||
// } | |||
// public long ReadLong() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return ReadLongInternal(type); | |||
// } | |||
// public ulong ReadULong() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (ulong)ReadLongInternal(type); | |||
// } | |||
// public long ReadLongInternal(ETFType type) | |||
// { | |||
// switch (type) | |||
// { | |||
// case ETFType.SMALL_INTEGER_EXT: | |||
// _stream.Read(_buffer, 0, 1); | |||
// return _buffer[0]; | |||
// case ETFType.INTEGER_EXT: | |||
// _stream.Read(_buffer, 0, 4); | |||
// return (_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | (_buffer[3]); | |||
// case ETFType.SMALL_BIG_EXT: | |||
// _stream.Read(_buffer, 0, 2); | |||
// bool isPositive = _buffer[0] == 0; | |||
// byte count = _buffer[1]; | |||
int shiftValue = (count - 1) * 8; | |||
ulong value = 0; | |||
_stream.Read(_buffer, 0, count); | |||
for (int i = 0; i < count; i++, shiftValue -= 8) | |||
value = value + _buffer[i] << shiftValue; | |||
if (!isPositive) | |||
return -(long)value; | |||
else | |||
return (long)value; | |||
} | |||
throw new InvalidDataException(); | |||
} | |||
// int shiftValue = (count - 1) * 8; | |||
// ulong value = 0; | |||
// _stream.Read(_buffer, 0, count); | |||
// for (int i = 0; i < count; i++, shiftValue -= 8) | |||
// value = value + _buffer[i] << shiftValue; | |||
// if (!isPositive) | |||
// return -(long)value; | |||
// else | |||
// return (long)value; | |||
// } | |||
// throw new InvalidDataException(); | |||
// } | |||
public float ReadSingle() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return (float)ReadDoubleInternal(type); | |||
} | |||
public double ReadDouble() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
return ReadDoubleInternal(type); | |||
} | |||
public double ReadDoubleInternal(ETFType type) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
// public float ReadSingle() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return (float)ReadDoubleInternal(type); | |||
// } | |||
// public double ReadDouble() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// return ReadDoubleInternal(type); | |||
// } | |||
// public double ReadDoubleInternal(ETFType type) | |||
// { | |||
// throw new NotImplementedException(); | |||
// } | |||
public bool? ReadNullableBool() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT) | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
switch (_buffer[0]) //Length | |||
{ | |||
case 3: | |||
if (ReadNil()) | |||
return null; | |||
break; | |||
case 4: | |||
ReadTrue(); | |||
return true; | |||
case 5: | |||
ReadFalse(); | |||
return false; | |||
} | |||
} | |||
throw new InvalidDataException(); | |||
} | |||
public int? ReadNullableSByte() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (sbyte)ReadLongInternal(type); | |||
} | |||
public uint? ReadNullableByte() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (byte)ReadLongInternal(type); | |||
} | |||
public int? ReadNullableShort() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (short)ReadLongInternal(type); | |||
} | |||
public uint? ReadNullableUShort() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (ushort)ReadLongInternal(type); | |||
} | |||
public int? ReadNullableInt() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (int)ReadLongInternal(type); | |||
} | |||
public uint? ReadNullableUInt() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (uint)ReadLongInternal(type); | |||
} | |||
public long? ReadNullableLong() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return ReadLongInternal(type); | |||
} | |||
public ulong? ReadNullableULong() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (ulong)ReadLongInternal(type); | |||
} | |||
public float? ReadNullableSingle() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return (float)ReadDoubleInternal(type); | |||
} | |||
public double? ReadNullableDouble() | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
ETFType type = (ETFType)_buffer[0]; | |||
if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
return ReadDoubleInternal(type); | |||
} | |||
// public bool? ReadNullableBool() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT) | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// switch (_buffer[0]) //Length | |||
// { | |||
// case 3: | |||
// if (ReadNil()) | |||
// return null; | |||
// break; | |||
// case 4: | |||
// ReadTrue(); | |||
// return true; | |||
// case 5: | |||
// ReadFalse(); | |||
// return false; | |||
// } | |||
// } | |||
// throw new InvalidDataException(); | |||
// } | |||
// public int? ReadNullableSByte() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (sbyte)ReadLongInternal(type); | |||
// } | |||
// public uint? ReadNullableByte() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (byte)ReadLongInternal(type); | |||
// } | |||
// public int? ReadNullableShort() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (short)ReadLongInternal(type); | |||
// } | |||
// public uint? ReadNullableUShort() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (ushort)ReadLongInternal(type); | |||
// } | |||
// public int? ReadNullableInt() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (int)ReadLongInternal(type); | |||
// } | |||
// public uint? ReadNullableUInt() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (uint)ReadLongInternal(type); | |||
// } | |||
// public long? ReadNullableLong() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return ReadLongInternal(type); | |||
// } | |||
// public ulong? ReadNullableULong() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (ulong)ReadLongInternal(type); | |||
// } | |||
// public float? ReadNullableSingle() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return (float)ReadDoubleInternal(type); | |||
// } | |||
// public double? ReadNullableDouble() | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// ETFType type = (ETFType)_buffer[0]; | |||
// if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; | |||
// return ReadDoubleInternal(type); | |||
// } | |||
public string ReadString() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public byte[] ReadByteArray() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
// public string ReadString() | |||
// { | |||
// throw new NotImplementedException(); | |||
// } | |||
// public byte[] ReadByteArray() | |||
// { | |||
// throw new NotImplementedException(); | |||
// } | |||
public T Read<T>() | |||
where T : new() | |||
{ | |||
var type = typeof(T); | |||
var typeInfo = type.GetTypeInfo(); | |||
var action = _deserializers.GetOrAdd(type, _ => CreateDeserializer<T>(type, typeInfo)) as Func<ETFReader, T>; | |||
return action(this); | |||
} | |||
/*public void Read<T, U>() | |||
where T : Nullable<T> | |||
where U : struct, new() | |||
{ | |||
}*/ | |||
public T[] ReadArray<T>() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
/*public object Read(object obj) | |||
{ | |||
throw new NotImplementedException(); | |||
}*/ | |||
// public T Read<T>() | |||
// where T : new() | |||
// { | |||
// var type = typeof(T); | |||
// var typeInfo = type.GetTypeInfo(); | |||
// var action = _deserializers.GetOrAdd(type, _ => CreateDeserializer<T>(type, typeInfo)) as Func<ETFReader, T>; | |||
// return action(this); | |||
// } | |||
// /*public void Read<T, U>() | |||
// where T : Nullable<T> | |||
// where U : struct, new() | |||
// { | |||
// }*/ | |||
// public T[] ReadArray<T>() | |||
// { | |||
// throw new NotImplementedException(); | |||
// } | |||
// public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>() | |||
// { | |||
// throw new NotImplementedException(); | |||
// } | |||
// /*public object Read(object obj) | |||
// { | |||
// throw new NotImplementedException(); | |||
// }*/ | |||
private bool ReadNil(bool ignoreLength = false) | |||
{ | |||
if (!ignoreLength) | |||
{ | |||
_stream.Read(_buffer, 0, 1); | |||
byte length = _buffer[0]; | |||
if (length != 3) return false; | |||
} | |||
// private bool ReadNil(bool ignoreLength = false) | |||
// { | |||
// if (!ignoreLength) | |||
// { | |||
// _stream.Read(_buffer, 0, 1); | |||
// byte length = _buffer[0]; | |||
// if (length != 3) return false; | |||
// } | |||
_stream.Read(_buffer, 0, 3); | |||
if (_buffer[0] == 'n' && _buffer[1] == 'i' && _buffer[2] == 'l') | |||
return true; | |||
// _stream.Read(_buffer, 0, 3); | |||
// if (_buffer[0] == 'n' && _buffer[1] == 'i' && _buffer[2] == 'l') | |||
// return true; | |||
return false; | |||
} | |||
// return false; | |||
// } | |||
#region Emit | |||
private static Func<ETFReader, T> CreateDeserializer<T>(Type type, TypeInfo typeInfo) | |||
where T : new() | |||
{ | |||
var method = new DynamicMethod("DeserializeETF", type, new[] { typeof(ETFReader) }, true); | |||
var generator = method.GetILGenerator(); | |||
// #region Emit | |||
// private static Func<ETFReader, T> CreateDeserializer<T>(Type type, TypeInfo typeInfo) | |||
// where T : new() | |||
// { | |||
// var method = new DynamicMethod("DeserializeETF", type, new[] { typeof(ETFReader) }, true); | |||
// var generator = method.GetILGenerator(); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
EmitReadValue(generator, type, typeInfo, true); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
// EmitReadValue(generator, type, typeInfo, true); | |||
generator.Emit(OpCodes.Ret); | |||
return method.CreateDelegate(typeof(Func<ETFReader, T>)) as Func<ETFReader, T>; | |||
} | |||
private static void EmitReadValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) | |||
{ | |||
//Convert enum types to their base type | |||
if (typeInfo.IsEnum) | |||
{ | |||
type = Enum.GetUnderlyingType(type); | |||
typeInfo = type.GetTypeInfo(); | |||
} | |||
//Primitives/Enums | |||
if (!typeInfo.IsEnum && IsType(type, typeof(sbyte), typeof(byte), typeof(short), | |||
typeof(ushort), typeof(int), typeof(uint), typeof(long), | |||
typeof(ulong), typeof(double), typeof(bool), typeof(string), | |||
typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), | |||
typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), | |||
typeof(bool?), typeof(float?), typeof(double?) | |||
/*typeof(object), typeof(DateTime)*/)) | |||
{ | |||
//No conversion needed | |||
generator.EmitCall(OpCodes.Call, GetReadMethod(type), null); | |||
} | |||
//Dictionaries | |||
/*else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Enumerable | |||
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Nullable Structs | |||
else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && | |||
typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Structs/Classes | |||
else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) | |||
{ | |||
if (isTop) | |||
{ | |||
typeInfo.ForEachField(f => | |||
{ | |||
string name; | |||
if (!f.IsPublic || !IsETFProperty(f, out name)) return; | |||
// generator.Emit(OpCodes.Ret); | |||
// return method.CreateDelegate(typeof(Func<ETFReader, T>)) as Func<ETFReader, T>; | |||
// } | |||
// private static void EmitReadValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) | |||
// { | |||
// //Convert enum types to their base type | |||
// if (typeInfo.IsEnum) | |||
// { | |||
// type = Enum.GetUnderlyingType(type); | |||
// typeInfo = type.GetTypeInfo(); | |||
// } | |||
// //Primitives/Enums | |||
// if (!typeInfo.IsEnum && IsType(type, typeof(sbyte), typeof(byte), typeof(short), | |||
// typeof(ushort), typeof(int), typeof(uint), typeof(long), | |||
// typeof(ulong), typeof(double), typeof(bool), typeof(string), | |||
// typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), | |||
// typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), | |||
// typeof(bool?), typeof(float?), typeof(double?) | |||
// /*typeof(object), typeof(DateTime)*/)) | |||
// { | |||
// //No conversion needed | |||
// generator.EmitCall(OpCodes.Call, GetReadMethod(type), null); | |||
// } | |||
// //Dictionaries | |||
// /*else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Enumerable | |||
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Nullable Structs | |||
// else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && | |||
// typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Structs/Classes | |||
// else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) | |||
// { | |||
// if (isTop) | |||
// { | |||
// typeInfo.ForEachField(f => | |||
// { | |||
// string name; | |||
// if (!f.IsPublic || !IsETFProperty(f, out name)) return; | |||
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name | |||
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj | |||
generator.Emit(OpCodes.Ldfld, f); //ETFReader(this), obj.fieldValue | |||
EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); | |||
}); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
// generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name | |||
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
// generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj | |||
// generator.Emit(OpCodes.Ldfld, f); //ETFReader(this), obj.fieldValue | |||
// EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); | |||
// }); | |||
typeInfo.ForEachProperty(p => | |||
{ | |||
string name; | |||
if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; | |||
// typeInfo.ForEachProperty(p => | |||
// { | |||
// string name; | |||
// if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; | |||
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name | |||
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj | |||
generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFReader(this), obj.propValue | |||
EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); | |||
}); | |||
} | |||
else | |||
{ | |||
//While we could drill deeper and make a large serializer that also serializes all subclasses, | |||
//it's more efficient to serialize on a per-type basis via another Write<T> call. | |||
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
}*/ | |||
//Unsupported (decimal, char) | |||
else | |||
throw new InvalidOperationException($"Deserializing {type.Name} is not supported."); | |||
} | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
// generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name | |||
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) | |||
// generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj | |||
// generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFReader(this), obj.propValue | |||
// EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); | |||
// }); | |||
// } | |||
// else | |||
// { | |||
// //While we could drill deeper and make a large serializer that also serializes all subclasses, | |||
// //it's more efficient to serialize on a per-type basis via another Write<T> call. | |||
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// }*/ | |||
// //Unsupported (decimal, char) | |||
// else | |||
// throw new InvalidOperationException($"Deserializing {type.Name} is not supported."); | |||
// } | |||
private static bool IsType(Type type, params Type[] types) | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
if (type == types[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
private static bool IsETFProperty(FieldInfo f, out string name) | |||
{ | |||
var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
if (attrib != null) | |||
{ | |||
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; | |||
return true; | |||
} | |||
name = null; | |||
return false; | |||
} | |||
private static bool IsETFProperty(PropertyInfo p, out string name) | |||
{ | |||
var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
if (attrib != null) | |||
{ | |||
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; | |||
return true; | |||
} | |||
name = null; | |||
return false; | |||
} | |||
// private static bool IsType(Type type, params Type[] types) | |||
// { | |||
// for (int i = 0; i < types.Length; i++) | |||
// { | |||
// if (type == types[i]) | |||
// return true; | |||
// } | |||
// return false; | |||
// } | |||
// private static bool IsETFProperty(FieldInfo f, out string name) | |||
// { | |||
// var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
// if (attrib != null) | |||
// { | |||
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; | |||
// return true; | |||
// } | |||
// name = null; | |||
// return false; | |||
// } | |||
// private static bool IsETFProperty(PropertyInfo p, out string name) | |||
// { | |||
// var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
// if (attrib != null) | |||
// { | |||
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; | |||
// return true; | |||
// } | |||
// name = null; | |||
// return false; | |||
// } | |||
private static MethodInfo GetReadMethod(string name) | |||
=> typeof(ETFReader).GetTypeInfo().GetDeclaredMethods(name).Single(); | |||
private static MethodInfo GetReadMethod(Type type) | |||
{ | |||
MethodInfo method; | |||
if (_readMethods.TryGetValue(type, out method)) | |||
return method; | |||
return null; | |||
} | |||
private static Dictionary<Type, MethodInfo> GetPrimitiveReadMethods() | |||
{ | |||
return new Dictionary<Type, MethodInfo> | |||
{ | |||
{ typeof(bool), GetReadMethod(nameof(ReadBool)) }, | |||
{ typeof(bool?), GetReadMethod(nameof(ReadNullableBool)) }, | |||
{ typeof(byte), GetReadMethod(nameof(ReadByte)) }, | |||
{ typeof(byte?), GetReadMethod(nameof(ReadNullableByte)) }, | |||
{ typeof(sbyte), GetReadMethod(nameof(ReadSByte)) }, | |||
{ typeof(sbyte?), GetReadMethod(nameof(ReadNullableSByte)) }, | |||
{ typeof(short), GetReadMethod(nameof(ReadShort)) }, | |||
{ typeof(short?), GetReadMethod(nameof(ReadNullableShort)) }, | |||
{ typeof(ushort), GetReadMethod(nameof(ReadUShort)) }, | |||
{ typeof(ushort?), GetReadMethod(nameof(ReadNullableUShort)) }, | |||
{ typeof(int), GetReadMethod(nameof(ReadInt)) }, | |||
{ typeof(int?), GetReadMethod(nameof(ReadNullableInt)) }, | |||
{ typeof(uint), GetReadMethod(nameof(ReadUInt)) }, | |||
{ typeof(uint?), GetReadMethod(nameof(ReadNullableUInt)) }, | |||
{ typeof(long), GetReadMethod(nameof(ReadLong)) }, | |||
{ typeof(long?), GetReadMethod(nameof(ReadNullableLong)) }, | |||
{ typeof(ulong), GetReadMethod(nameof(ReadULong)) }, | |||
{ typeof(ulong?), GetReadMethod(nameof(ReadNullableULong)) }, | |||
{ typeof(float), GetReadMethod(nameof(ReadSingle)) }, | |||
{ typeof(float?), GetReadMethod(nameof(ReadNullableSingle)) }, | |||
{ typeof(double), GetReadMethod(nameof(ReadDouble)) }, | |||
{ typeof(double?), GetReadMethod(nameof(ReadNullableDouble)) }, | |||
}; | |||
} | |||
#endregion | |||
// private static MethodInfo GetReadMethod(string name) | |||
// => typeof(ETFReader).GetTypeInfo().GetDeclaredMethods(name).Single(); | |||
// private static MethodInfo GetReadMethod(Type type) | |||
// { | |||
// MethodInfo method; | |||
// if (_readMethods.TryGetValue(type, out method)) | |||
// return method; | |||
// return null; | |||
// } | |||
// private static Dictionary<Type, MethodInfo> GetPrimitiveReadMethods() | |||
// { | |||
// return new Dictionary<Type, MethodInfo> | |||
// { | |||
// { typeof(bool), GetReadMethod(nameof(ReadBool)) }, | |||
// { typeof(bool?), GetReadMethod(nameof(ReadNullableBool)) }, | |||
// { typeof(byte), GetReadMethod(nameof(ReadByte)) }, | |||
// { typeof(byte?), GetReadMethod(nameof(ReadNullableByte)) }, | |||
// { typeof(sbyte), GetReadMethod(nameof(ReadSByte)) }, | |||
// { typeof(sbyte?), GetReadMethod(nameof(ReadNullableSByte)) }, | |||
// { typeof(short), GetReadMethod(nameof(ReadShort)) }, | |||
// { typeof(short?), GetReadMethod(nameof(ReadNullableShort)) }, | |||
// { typeof(ushort), GetReadMethod(nameof(ReadUShort)) }, | |||
// { typeof(ushort?), GetReadMethod(nameof(ReadNullableUShort)) }, | |||
// { typeof(int), GetReadMethod(nameof(ReadInt)) }, | |||
// { typeof(int?), GetReadMethod(nameof(ReadNullableInt)) }, | |||
// { typeof(uint), GetReadMethod(nameof(ReadUInt)) }, | |||
// { typeof(uint?), GetReadMethod(nameof(ReadNullableUInt)) }, | |||
// { typeof(long), GetReadMethod(nameof(ReadLong)) }, | |||
// { typeof(long?), GetReadMethod(nameof(ReadNullableLong)) }, | |||
// { typeof(ulong), GetReadMethod(nameof(ReadULong)) }, | |||
// { typeof(ulong?), GetReadMethod(nameof(ReadNullableULong)) }, | |||
// { typeof(float), GetReadMethod(nameof(ReadSingle)) }, | |||
// { typeof(float?), GetReadMethod(nameof(ReadNullableSingle)) }, | |||
// { typeof(double), GetReadMethod(nameof(ReadDouble)) }, | |||
// { typeof(double?), GetReadMethod(nameof(ReadNullableDouble)) }, | |||
// }; | |||
// } | |||
// #endregion | |||
#region IDisposable | |||
private bool _isDisposed = false; | |||
// #region IDisposable | |||
// private bool _isDisposed = false; | |||
protected virtual void Dispose(bool disposing) | |||
{ | |||
if (!_isDisposed) | |||
{ | |||
if (disposing) | |||
{ | |||
if (_leaveOpen) | |||
_stream.Flush(); | |||
else | |||
_stream.Dispose(); | |||
} | |||
_isDisposed = true; | |||
} | |||
} | |||
// protected virtual void Dispose(bool disposing) | |||
// { | |||
// if (!_isDisposed) | |||
// { | |||
// if (disposing) | |||
// { | |||
// if (_leaveOpen) | |||
// _stream.Flush(); | |||
// else | |||
// _stream.Dispose(); | |||
// } | |||
// _isDisposed = true; | |||
// } | |||
// } | |||
public void Dispose() => Dispose(true); | |||
#endregion | |||
} | |||
} | |||
// public void Dispose() => Dispose(true); | |||
// #endregion | |||
// } | |||
//} |
@@ -1,482 +1,482 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Reflection; | |||
using System.Reflection.Emit; | |||
using System.Text; | |||
//using Newtonsoft.Json; | |||
//using System; | |||
//using System.Collections.Concurrent; | |||
//using System.Collections.Generic; | |||
//using System.IO; | |||
//using System.Linq; | |||
//using System.Reflection; | |||
//using System.Reflection.Emit; | |||
//using System.Text; | |||
namespace Discord.ETF | |||
{ | |||
public unsafe class ETFWriter : IDisposable | |||
{ | |||
private static readonly ConcurrentDictionary<Type, Delegate> _serializers = new ConcurrentDictionary<Type, Delegate>(); | |||
private static readonly ConcurrentDictionary<Type, Delegate> _indirectSerializers = new ConcurrentDictionary<Type, Delegate>(); | |||
//namespace Discord.ETF | |||
//{ | |||
// public unsafe class ETFWriter : IDisposable | |||
// { | |||
// private static readonly ConcurrentDictionary<Type, Delegate> _serializers = new ConcurrentDictionary<Type, Delegate>(); | |||
// private static readonly ConcurrentDictionary<Type, Delegate> _indirectSerializers = new ConcurrentDictionary<Type, Delegate>(); | |||
private static readonly byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' }; | |||
private static readonly byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; | |||
private static readonly byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' }; | |||
// private static readonly byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' }; | |||
// private static readonly byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; | |||
// private static readonly byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' }; | |||
private static readonly MethodInfo _writeTMethod = GetGenericWriteMethod(null); | |||
private static readonly MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>)); | |||
private static readonly MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>)); | |||
private static readonly MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>)); | |||
private static readonly DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | |||
// private static readonly MethodInfo _writeTMethod = GetGenericWriteMethod(null); | |||
// private static readonly MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>)); | |||
// private static readonly MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>)); | |||
// private static readonly MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>)); | |||
// private static readonly DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | |||
private readonly Stream _stream; | |||
private readonly byte[] _buffer; | |||
private readonly bool _leaveOpen; | |||
private readonly Encoding _encoding; | |||
// private readonly Stream _stream; | |||
// private readonly byte[] _buffer; | |||
// private readonly bool _leaveOpen; | |||
// private readonly Encoding _encoding; | |||
public virtual Stream BaseStream | |||
{ | |||
get | |||
{ | |||
Flush(); | |||
return _stream; | |||
} | |||
} | |||
// public virtual Stream BaseStream | |||
// { | |||
// get | |||
// { | |||
// Flush(); | |||
// return _stream; | |||
// } | |||
// } | |||
public ETFWriter(Stream stream, bool leaveOpen = false) | |||
{ | |||
if (stream == null) throw new ArgumentNullException(nameof(stream)); | |||
// public ETFWriter(Stream stream, bool leaveOpen = false) | |||
// { | |||
// if (stream == null) throw new ArgumentNullException(nameof(stream)); | |||
_stream = stream; | |||
_leaveOpen = leaveOpen; | |||
_buffer = new byte[11]; | |||
_encoding = Encoding.UTF8; | |||
} | |||
// _stream = stream; | |||
// _leaveOpen = leaveOpen; | |||
// _buffer = new byte[11]; | |||
// _encoding = Encoding.UTF8; | |||
// } | |||
public void Write(bool value) | |||
{ | |||
if (value) | |||
_stream.Write(_trueBytes, 0, _trueBytes.Length); | |||
else | |||
_stream.Write(_falseBytes, 0, _falseBytes.Length); | |||
} | |||
public void Write(sbyte value) => Write((long)value); | |||
public void Write(byte value) => Write((ulong)value); | |||
public void Write(short value) => Write((long)value); | |||
public void Write(ushort value) => Write((ulong)value); | |||
public void Write(int value) => Write((long)value); | |||
public void Write(uint value) => Write((ulong)value); | |||
public void Write(long value) | |||
{ | |||
if (value >= byte.MinValue && value <= byte.MaxValue) | |||
{ | |||
_buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; | |||
_buffer[1] = (byte)value; | |||
_stream.Write(_buffer, 0, 2); | |||
} | |||
else if (value >= int.MinValue && value <= int.MaxValue) | |||
{ | |||
//TODO: Does this encode negatives correctly? | |||
_buffer[0] = (byte)ETFType.INTEGER_EXT; | |||
_buffer[1] = (byte)(value >> 24); | |||
_buffer[2] = (byte)(value >> 16); | |||
_buffer[3] = (byte)(value >> 8); | |||
_buffer[4] = (byte)value; | |||
_stream.Write(_buffer, 0, 5); | |||
} | |||
else | |||
{ | |||
_buffer[0] = (byte)ETFType.SMALL_BIG_EXT; | |||
if (value < 0) | |||
{ | |||
_buffer[2] = 1; //Is negative | |||
value = -value; | |||
} | |||
// public void Write(bool value) | |||
// { | |||
// if (value) | |||
// _stream.Write(_trueBytes, 0, _trueBytes.Length); | |||
// else | |||
// _stream.Write(_falseBytes, 0, _falseBytes.Length); | |||
// } | |||
// public void Write(sbyte value) => Write((long)value); | |||
// public void Write(byte value) => Write((ulong)value); | |||
// public void Write(short value) => Write((long)value); | |||
// public void Write(ushort value) => Write((ulong)value); | |||
// public void Write(int value) => Write((long)value); | |||
// public void Write(uint value) => Write((ulong)value); | |||
// public void Write(long value) | |||
// { | |||
// if (value >= byte.MinValue && value <= byte.MaxValue) | |||
// { | |||
// _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; | |||
// _buffer[1] = (byte)value; | |||
// _stream.Write(_buffer, 0, 2); | |||
// } | |||
// else if (value >= int.MinValue && value <= int.MaxValue) | |||
// { | |||
// //TODO: Does this encode negatives correctly? | |||
// _buffer[0] = (byte)ETFType.INTEGER_EXT; | |||
// _buffer[1] = (byte)(value >> 24); | |||
// _buffer[2] = (byte)(value >> 16); | |||
// _buffer[3] = (byte)(value >> 8); | |||
// _buffer[4] = (byte)value; | |||
// _stream.Write(_buffer, 0, 5); | |||
// } | |||
// else | |||
// { | |||
// _buffer[0] = (byte)ETFType.SMALL_BIG_EXT; | |||
// if (value < 0) | |||
// { | |||
// _buffer[2] = 1; //Is negative | |||
// value = -value; | |||
// } | |||
byte bytes = 0; | |||
while (value > 0) | |||
_buffer[3 + bytes++] = (byte)(value >>= 8); | |||
_buffer[1] = bytes; //Encoded bytes | |||
// byte bytes = 0; | |||
// while (value > 0) | |||
// _buffer[3 + bytes++] = (byte)(value >>= 8); | |||
// _buffer[1] = bytes; //Encoded bytes | |||
_stream.Write(_buffer, 0, 3 + bytes); | |||
} | |||
} | |||
public void Write(ulong value) | |||
{ | |||
if (value <= byte.MaxValue) | |||
{ | |||
_buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; | |||
_buffer[1] = (byte)value; | |||
_stream.Write(_buffer, 0, 2); | |||
} | |||
else if (value <= int.MaxValue) | |||
{ | |||
_buffer[0] = (byte)ETFType.INTEGER_EXT; | |||
_buffer[1] = (byte)(value >> 24); | |||
_buffer[2] = (byte)(value >> 16); | |||
_buffer[3] = (byte)(value >> 8); | |||
_buffer[4] = (byte)value; | |||
_stream.Write(_buffer, 0, 5); | |||
} | |||
else | |||
{ | |||
_buffer[0] = (byte)ETFType.SMALL_BIG_EXT; | |||
_buffer[2] = 0; //Always positive | |||
// _stream.Write(_buffer, 0, 3 + bytes); | |||
// } | |||
// } | |||
// public void Write(ulong value) | |||
// { | |||
// if (value <= byte.MaxValue) | |||
// { | |||
// _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; | |||
// _buffer[1] = (byte)value; | |||
// _stream.Write(_buffer, 0, 2); | |||
// } | |||
// else if (value <= int.MaxValue) | |||
// { | |||
// _buffer[0] = (byte)ETFType.INTEGER_EXT; | |||
// _buffer[1] = (byte)(value >> 24); | |||
// _buffer[2] = (byte)(value >> 16); | |||
// _buffer[3] = (byte)(value >> 8); | |||
// _buffer[4] = (byte)value; | |||
// _stream.Write(_buffer, 0, 5); | |||
// } | |||
// else | |||
// { | |||
// _buffer[0] = (byte)ETFType.SMALL_BIG_EXT; | |||
// _buffer[2] = 0; //Always positive | |||
byte bytes = 0; | |||
while (value > 0) | |||
_buffer[3 + bytes++] = (byte)(value >>= 8); | |||
_buffer[1] = bytes; //Encoded bytes | |||
// byte bytes = 0; | |||
// while (value > 0) | |||
// _buffer[3 + bytes++] = (byte)(value >>= 8); | |||
// _buffer[1] = bytes; //Encoded bytes | |||
_stream.Write(_buffer, 0, 3 + bytes); | |||
} | |||
} | |||
// _stream.Write(_buffer, 0, 3 + bytes); | |||
// } | |||
// } | |||
public void Write(float value) => Write((double)value); | |||
public void Write(double value) | |||
{ | |||
ulong value2 = *(ulong*)&value; | |||
_buffer[0] = (byte)ETFType.NEW_FLOAT_EXT; | |||
_buffer[1] = (byte)(value2 >> 56); | |||
_buffer[2] = (byte)(value2 >> 48); | |||
_buffer[3] = (byte)(value2 >> 40); | |||
_buffer[4] = (byte)(value2 >> 32); | |||
_buffer[5] = (byte)(value2 >> 24); | |||
_buffer[6] = (byte)(value2 >> 16); | |||
_buffer[7] = (byte)(value2 >> 8); | |||
_buffer[8] = (byte)value2; | |||
_stream.Write(_buffer, 0, 9); | |||
} | |||
// public void Write(float value) => Write((double)value); | |||
// public void Write(double value) | |||
// { | |||
// ulong value2 = *(ulong*)&value; | |||
// _buffer[0] = (byte)ETFType.NEW_FLOAT_EXT; | |||
// _buffer[1] = (byte)(value2 >> 56); | |||
// _buffer[2] = (byte)(value2 >> 48); | |||
// _buffer[3] = (byte)(value2 >> 40); | |||
// _buffer[4] = (byte)(value2 >> 32); | |||
// _buffer[5] = (byte)(value2 >> 24); | |||
// _buffer[6] = (byte)(value2 >> 16); | |||
// _buffer[7] = (byte)(value2 >> 8); | |||
// _buffer[8] = (byte)value2; | |||
// _stream.Write(_buffer, 0, 9); | |||
// } | |||
public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond)); | |||
// public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond)); | |||
public void Write(bool? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(sbyte? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } | |||
public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
public void Write(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } | |||
public void Write(ushort? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
public void Write(int? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(uint? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
public void Write(long? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(float? value) { if (value.HasValue) Write((double)value.Value); else WriteNil(); } | |||
public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(bool? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(sbyte? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } | |||
// public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
// public void Write(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } | |||
// public void Write(ushort? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
// public void Write(int? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(uint? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } | |||
// public void Write(long? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
// public void Write(float? value) { if (value.HasValue) Write((double)value.Value); else WriteNil(); } | |||
// public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } | |||
public void Write(string value) | |||
{ | |||
if (value != null) | |||
{ | |||
var bytes = _encoding.GetBytes(value); | |||
int count = bytes.Length; | |||
_buffer[0] = (byte)ETFType.BINARY_EXT; | |||
_buffer[1] = (byte)(count >> 24); | |||
_buffer[2] = (byte)(count >> 16); | |||
_buffer[3] = (byte)(count >> 8); | |||
_buffer[4] = (byte)count; | |||
_stream.Write(_buffer, 0, 5); | |||
_stream.Write(bytes, 0, bytes.Length); | |||
} | |||
else | |||
WriteNil(); | |||
} | |||
public void Write(byte[] value) | |||
{ | |||
if (value != null) | |||
{ | |||
int count = value.Length; | |||
_buffer[0] = (byte)ETFType.BINARY_EXT; | |||
_buffer[1] = (byte)(count >> 24); | |||
_buffer[2] = (byte)(count >> 16); | |||
_buffer[3] = (byte)(count >> 8); | |||
_buffer[4] = (byte)count; | |||
_stream.Write(_buffer, 0, 5); | |||
_stream.Write(value, 0, value.Length); | |||
} | |||
else | |||
WriteNil(); | |||
} | |||
// public void Write(string value) | |||
// { | |||
// if (value != null) | |||
// { | |||
// var bytes = _encoding.GetBytes(value); | |||
// int count = bytes.Length; | |||
// _buffer[0] = (byte)ETFType.BINARY_EXT; | |||
// _buffer[1] = (byte)(count >> 24); | |||
// _buffer[2] = (byte)(count >> 16); | |||
// _buffer[3] = (byte)(count >> 8); | |||
// _buffer[4] = (byte)count; | |||
// _stream.Write(_buffer, 0, 5); | |||
// _stream.Write(bytes, 0, bytes.Length); | |||
// } | |||
// else | |||
// WriteNil(); | |||
// } | |||
// public void Write(byte[] value) | |||
// { | |||
// if (value != null) | |||
// { | |||
// int count = value.Length; | |||
// _buffer[0] = (byte)ETFType.BINARY_EXT; | |||
// _buffer[1] = (byte)(count >> 24); | |||
// _buffer[2] = (byte)(count >> 16); | |||
// _buffer[3] = (byte)(count >> 8); | |||
// _buffer[4] = (byte)count; | |||
// _stream.Write(_buffer, 0, 5); | |||
// _stream.Write(value, 0, value.Length); | |||
// } | |||
// else | |||
// WriteNil(); | |||
// } | |||
public void Write<T>(T obj) | |||
{ | |||
var type = typeof(T); | |||
var typeInfo = type.GetTypeInfo(); | |||
var action = _serializers.GetOrAdd(type, _ => CreateSerializer<T>(type, typeInfo, false)) as Action<ETFWriter, T>; | |||
action(this, obj); | |||
} | |||
public void Write<T>(T? obj) | |||
where T : struct | |||
{ | |||
if (obj != null) | |||
Write(obj.Value); | |||
else | |||
WriteNil(); | |||
} | |||
public void Write<T>(IEnumerable<T> obj) | |||
{ | |||
if (obj != null) | |||
{ | |||
var array = obj.ToArray(); | |||
int length = array.Length; | |||
_buffer[0] = (byte)ETFType.LIST_EXT; | |||
_buffer[1] = (byte)(length >> 24); | |||
_buffer[2] = (byte)(length >> 16); | |||
_buffer[3] = (byte)(length >> 8); | |||
_buffer[4] = (byte)length; | |||
_stream.Write(_buffer, 0, 5); | |||
// public void Write<T>(T obj) | |||
// { | |||
// var type = typeof(T); | |||
// var typeInfo = type.GetTypeInfo(); | |||
// var action = _serializers.GetOrAdd(type, _ => CreateSerializer<T>(type, typeInfo, false)) as Action<ETFWriter, T>; | |||
// action(this, obj); | |||
// } | |||
// public void Write<T>(T? obj) | |||
// where T : struct | |||
// { | |||
// if (obj != null) | |||
// Write(obj.Value); | |||
// else | |||
// WriteNil(); | |||
// } | |||
// public void Write<T>(IEnumerable<T> obj) | |||
// { | |||
// if (obj != null) | |||
// { | |||
// var array = obj.ToArray(); | |||
// int length = array.Length; | |||
// _buffer[0] = (byte)ETFType.LIST_EXT; | |||
// _buffer[1] = (byte)(length >> 24); | |||
// _buffer[2] = (byte)(length >> 16); | |||
// _buffer[3] = (byte)(length >> 8); | |||
// _buffer[4] = (byte)length; | |||
// _stream.Write(_buffer, 0, 5); | |||
for (int i = 0; i < array.Length; i++) | |||
Write(array[i]); | |||
// for (int i = 0; i < array.Length; i++) | |||
// Write(array[i]); | |||
_buffer[0] = (byte)ETFType.NIL_EXT; | |||
_stream.Write(_buffer, 0, 1); | |||
} | |||
else | |||
WriteNil(); | |||
} | |||
public void Write<TKey, TValue>(IDictionary<TKey, TValue> obj) | |||
{ | |||
if (obj != null) | |||
{ | |||
int length = obj.Count; | |||
_buffer[0] = (byte)ETFType.MAP_EXT; | |||
_buffer[1] = (byte)(length >> 24); | |||
_buffer[2] = (byte)(length >> 16); | |||
_buffer[3] = (byte)(length >> 8); | |||
_buffer[4] = (byte)length; | |||
_stream.Write(_buffer, 0, 5); | |||
// _buffer[0] = (byte)ETFType.NIL_EXT; | |||
// _stream.Write(_buffer, 0, 1); | |||
// } | |||
// else | |||
// WriteNil(); | |||
// } | |||
// public void Write<TKey, TValue>(IDictionary<TKey, TValue> obj) | |||
// { | |||
// if (obj != null) | |||
// { | |||
// int length = obj.Count; | |||
// _buffer[0] = (byte)ETFType.MAP_EXT; | |||
// _buffer[1] = (byte)(length >> 24); | |||
// _buffer[2] = (byte)(length >> 16); | |||
// _buffer[3] = (byte)(length >> 8); | |||
// _buffer[4] = (byte)length; | |||
// _stream.Write(_buffer, 0, 5); | |||
foreach (var pair in obj) | |||
{ | |||
Write(pair.Key); | |||
Write(pair.Value); | |||
} | |||
} | |||
else | |||
WriteNil(); | |||
} | |||
public void Write(object obj) | |||
{ | |||
if (obj != null) | |||
{ | |||
var type = obj.GetType(); | |||
var typeInfo = type.GetTypeInfo(); | |||
var action = _indirectSerializers.GetOrAdd(type, _ => CreateSerializer<object>(type, typeInfo, true)) as Action<ETFWriter, object>; | |||
action(this, obj); | |||
} | |||
else | |||
WriteNil(); | |||
} | |||
// foreach (var pair in obj) | |||
// { | |||
// Write(pair.Key); | |||
// Write(pair.Value); | |||
// } | |||
// } | |||
// else | |||
// WriteNil(); | |||
// } | |||
// public void Write(object obj) | |||
// { | |||
// if (obj != null) | |||
// { | |||
// var type = obj.GetType(); | |||
// var typeInfo = type.GetTypeInfo(); | |||
// var action = _indirectSerializers.GetOrAdd(type, _ => CreateSerializer<object>(type, typeInfo, true)) as Action<ETFWriter, object>; | |||
// action(this, obj); | |||
// } | |||
// else | |||
// WriteNil(); | |||
// } | |||
private void WriteNil() => _stream.Write(_nilBytes, 0, _nilBytes.Length); | |||
// private void WriteNil() => _stream.Write(_nilBytes, 0, _nilBytes.Length); | |||
public virtual void Flush() => _stream.Flush(); | |||
public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin); | |||
// public virtual void Flush() => _stream.Flush(); | |||
// public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin); | |||
#region Emit | |||
private static Action<ETFWriter, T> CreateSerializer<T>(Type type, TypeInfo typeInfo, bool isDirect) | |||
{ | |||
var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF", | |||
null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true); | |||
var generator = method.GetILGenerator(); | |||
// #region Emit | |||
// private static Action<ETFWriter, T> CreateSerializer<T>(Type type, TypeInfo typeInfo, bool isDirect) | |||
// { | |||
// var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF", | |||
// null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true); | |||
// var generator = method.GetILGenerator(); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), value | |||
if (!isDirect) | |||
{ | |||
if (typeInfo.IsValueType) //Unbox value types | |||
generator.Emit(OpCodes.Unbox_Any, type); //ETFWriter(this), real_value | |||
else //Cast reference types | |||
generator.Emit(OpCodes.Castclass, type); //ETFWriter(this), real_value | |||
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(type), null); //Call generic version | |||
} | |||
else | |||
EmitWriteValue(generator, type, typeInfo, true); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), value | |||
// if (!isDirect) | |||
// { | |||
// if (typeInfo.IsValueType) //Unbox value types | |||
// generator.Emit(OpCodes.Unbox_Any, type); //ETFWriter(this), real_value | |||
// else //Cast reference types | |||
// generator.Emit(OpCodes.Castclass, type); //ETFWriter(this), real_value | |||
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(type), null); //Call generic version | |||
// } | |||
// else | |||
// EmitWriteValue(generator, type, typeInfo, true); | |||
generator.Emit(OpCodes.Ret); | |||
return method.CreateDelegate(typeof(Action<ETFWriter, T>)) as Action<ETFWriter, T>; | |||
} | |||
private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) | |||
{ | |||
//Convert enum types to their base type | |||
if (typeInfo.IsEnum) | |||
{ | |||
type = Enum.GetUnderlyingType(type); | |||
typeInfo = type.GetTypeInfo(); | |||
} | |||
// generator.Emit(OpCodes.Ret); | |||
// return method.CreateDelegate(typeof(Action<ETFWriter, T>)) as Action<ETFWriter, T>; | |||
// } | |||
// private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) | |||
// { | |||
// //Convert enum types to their base type | |||
// if (typeInfo.IsEnum) | |||
// { | |||
// type = Enum.GetUnderlyingType(type); | |||
// typeInfo = type.GetTypeInfo(); | |||
// } | |||
//Primitives/Enums | |||
Type targetType = null; | |||
if (!typeInfo.IsEnum && IsType(type, typeof(long), typeof(ulong), typeof(double), typeof(bool), typeof(string), | |||
typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), | |||
typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), | |||
typeof(bool?), typeof(float?), typeof(double?), | |||
typeof(object), typeof(DateTime))) | |||
{ | |||
//No conversion needed | |||
targetType = type; | |||
} | |||
else if (IsType(type, typeof(sbyte), typeof(short), typeof(int))) | |||
{ | |||
//Convert to long | |||
generator.Emit(OpCodes.Conv_I8); | |||
targetType = typeof(long); | |||
} | |||
else if (IsType(type, typeof(byte), typeof(ushort), typeof(uint))) | |||
{ | |||
//Convert to ulong | |||
generator.Emit(OpCodes.Conv_U8); | |||
targetType = typeof(ulong); | |||
} | |||
else if (IsType(type, typeof(float))) | |||
{ | |||
//Convert to double | |||
generator.Emit(OpCodes.Conv_R8); | |||
targetType = typeof(double); | |||
} | |||
if (targetType != null) | |||
generator.EmitCall(OpCodes.Call, GetWriteMethod(targetType), null); | |||
// //Primitives/Enums | |||
// Type targetType = null; | |||
// if (!typeInfo.IsEnum && IsType(type, typeof(long), typeof(ulong), typeof(double), typeof(bool), typeof(string), | |||
// typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), | |||
// typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), | |||
// typeof(bool?), typeof(float?), typeof(double?), | |||
// typeof(object), typeof(DateTime))) | |||
// { | |||
// //No conversion needed | |||
// targetType = type; | |||
// } | |||
// else if (IsType(type, typeof(sbyte), typeof(short), typeof(int))) | |||
// { | |||
// //Convert to long | |||
// generator.Emit(OpCodes.Conv_I8); | |||
// targetType = typeof(long); | |||
// } | |||
// else if (IsType(type, typeof(byte), typeof(ushort), typeof(uint))) | |||
// { | |||
// //Convert to ulong | |||
// generator.Emit(OpCodes.Conv_U8); | |||
// targetType = typeof(ulong); | |||
// } | |||
// else if (IsType(type, typeof(float))) | |||
// { | |||
// //Convert to double | |||
// generator.Emit(OpCodes.Conv_R8); | |||
// targetType = typeof(double); | |||
// } | |||
// if (targetType != null) | |||
// generator.EmitCall(OpCodes.Call, GetWriteMethod(targetType), null); | |||
//Dictionaries | |||
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Enumerable | |||
else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
.Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Nullable Structs | |||
else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && | |||
typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) | |||
{ | |||
generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
//Structs/Classes | |||
else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) | |||
{ | |||
if (isTop) | |||
{ | |||
typeInfo.ForEachField(f => | |||
{ | |||
string name; | |||
if (!f.IsPublic || !IsETFProperty(f, out name)) return; | |||
// //Dictionaries | |||
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Enumerable | |||
// else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces | |||
// .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Nullable Structs | |||
// else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && | |||
// typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) | |||
// { | |||
// generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// //Structs/Classes | |||
// else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) | |||
// { | |||
// if (isTop) | |||
// { | |||
// typeInfo.ForEachField(f => | |||
// { | |||
// string name; | |||
// if (!f.IsPublic || !IsETFProperty(f, out name)) return; | |||
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name | |||
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj | |||
generator.Emit(OpCodes.Ldfld, f); //ETFWriter(this), obj.fieldValue | |||
EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); | |||
}); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
// generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name | |||
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj | |||
// generator.Emit(OpCodes.Ldfld, f); //ETFWriter(this), obj.fieldValue | |||
// EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); | |||
// }); | |||
typeInfo.ForEachProperty(p => | |||
{ | |||
string name; | |||
if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; | |||
// typeInfo.ForEachProperty(p => | |||
// { | |||
// string name; | |||
// if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; | |||
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name | |||
generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj | |||
generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFWriter(this), obj.propValue | |||
EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); | |||
}); | |||
} | |||
else | |||
{ | |||
//While we could drill deeper and make a large serializer that also serializes all subclasses, | |||
//it's more efficient to serialize on a per-type basis via another Write<T> call. | |||
generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
} | |||
} | |||
//Unsupported (decimal, char) | |||
else | |||
throw new InvalidOperationException($"Serializing {type.Name} is not supported."); | |||
} | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
// generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name | |||
// generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); | |||
// generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) | |||
// generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj | |||
// generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFWriter(this), obj.propValue | |||
// EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); | |||
// }); | |||
// } | |||
// else | |||
// { | |||
// //While we could drill deeper and make a large serializer that also serializes all subclasses, | |||
// //it's more efficient to serialize on a per-type basis via another Write<T> call. | |||
// generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); | |||
// } | |||
// } | |||
// //Unsupported (decimal, char) | |||
// else | |||
// throw new InvalidOperationException($"Serializing {type.Name} is not supported."); | |||
// } | |||
private static bool IsType(Type type, params Type[] types) | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
if (type == types[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
private static bool IsETFProperty(FieldInfo f, out string name) | |||
{ | |||
var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
if (attrib != null) | |||
{ | |||
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; | |||
return true; | |||
} | |||
name = null; | |||
return false; | |||
} | |||
private static bool IsETFProperty(PropertyInfo p, out string name) | |||
{ | |||
var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
if (attrib != null) | |||
{ | |||
name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; | |||
return true; | |||
} | |||
name = null; | |||
return false; | |||
} | |||
// private static bool IsType(Type type, params Type[] types) | |||
// { | |||
// for (int i = 0; i < types.Length; i++) | |||
// { | |||
// if (type == types[i]) | |||
// return true; | |||
// } | |||
// return false; | |||
// } | |||
// private static bool IsETFProperty(FieldInfo f, out string name) | |||
// { | |||
// var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
// if (attrib != null) | |||
// { | |||
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; | |||
// return true; | |||
// } | |||
// name = null; | |||
// return false; | |||
// } | |||
// private static bool IsETFProperty(PropertyInfo p, out string name) | |||
// { | |||
// var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); | |||
// if (attrib != null) | |||
// { | |||
// name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; | |||
// return true; | |||
// } | |||
// name = null; | |||
// return false; | |||
// } | |||
private static MethodInfo GetWriteMethod(Type paramType) | |||
{ | |||
return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write)) | |||
.Where(x => x.GetParameters()[0].ParameterType == paramType) | |||
.Single(); | |||
} | |||
private static MethodInfo GetGenericWriteMethod(Type genericType) | |||
{ | |||
if (genericType == null) | |||
{ | |||
return typeof(ETFWriter).GetTypeInfo() | |||
.GetDeclaredMethods(nameof(Write)) | |||
.Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0]) | |||
.Single(); | |||
} | |||
else | |||
{ | |||
return typeof(ETFWriter).GetTypeInfo() | |||
.GetDeclaredMethods(nameof(Write)) | |||
.Where(x => | |||
{ | |||
if (!x.IsGenericMethodDefinition) return false; | |||
var p = x.GetParameters()[0].ParameterType.GetTypeInfo(); | |||
return p.IsGenericType && p.GetGenericTypeDefinition() == genericType; | |||
}) | |||
.Single(); | |||
} | |||
} | |||
#endregion | |||
// private static MethodInfo GetWriteMethod(Type paramType) | |||
// { | |||
// return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write)) | |||
// .Where(x => x.GetParameters()[0].ParameterType == paramType) | |||
// .Single(); | |||
// } | |||
// private static MethodInfo GetGenericWriteMethod(Type genericType) | |||
// { | |||
// if (genericType == null) | |||
// { | |||
// return typeof(ETFWriter).GetTypeInfo() | |||
// .GetDeclaredMethods(nameof(Write)) | |||
// .Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0]) | |||
// .Single(); | |||
// } | |||
// else | |||
// { | |||
// return typeof(ETFWriter).GetTypeInfo() | |||
// .GetDeclaredMethods(nameof(Write)) | |||
// .Where(x => | |||
// { | |||
// if (!x.IsGenericMethodDefinition) return false; | |||
// var p = x.GetParameters()[0].ParameterType.GetTypeInfo(); | |||
// return p.IsGenericType && p.GetGenericTypeDefinition() == genericType; | |||
// }) | |||
// .Single(); | |||
// } | |||
// } | |||
// #endregion | |||
#region IDisposable | |||
private bool _isDisposed = false; | |||
// #region IDisposable | |||
// private bool _isDisposed = false; | |||
protected virtual void Dispose(bool disposing) | |||
{ | |||
if (!_isDisposed) | |||
{ | |||
if (disposing) | |||
{ | |||
if (_leaveOpen) | |||
_stream.Flush(); | |||
else | |||
_stream.Dispose(); | |||
} | |||
_isDisposed = true; | |||
} | |||
} | |||
// protected virtual void Dispose(bool disposing) | |||
// { | |||
// if (!_isDisposed) | |||
// { | |||
// if (disposing) | |||
// { | |||
// if (_leaveOpen) | |||
// _stream.Flush(); | |||
// else | |||
// _stream.Dispose(); | |||
// } | |||
// _isDisposed = true; | |||
// } | |||
// } | |||
public void Dispose() => Dispose(true); | |||
#endregion | |||
} | |||
} | |||
// public void Dispose() => Dispose(true); | |||
// #endregion | |||
// } | |||
//} |
@@ -7,36 +7,36 @@ namespace Discord.Logging | |||
LogSeverity Level { get; } | |||
void Log(LogSeverity severity, string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Log(LogSeverity severity, FormattableString message, Exception exception = null); | |||
#endif | |||
void Error(string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Error(FormattableString message, Exception exception = null); | |||
#endif | |||
void Error(Exception exception); | |||
void Warning(string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Warning(FormattableString message, Exception exception = null); | |||
#endif | |||
void Warning(Exception exception); | |||
void Info(string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Info(FormattableString message, Exception exception = null); | |||
#endif | |||
void Info(Exception exception); | |||
void Verbose(string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Verbose(FormattableString message, Exception exception = null); | |||
#endif | |||
void Verbose(Exception exception); | |||
void Debug(string message, Exception exception = null); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
void Debug(FormattableString message, Exception exception = null); | |||
#endif | |||
void Debug(Exception exception); | |||
@@ -25,7 +25,7 @@ namespace Discord.Logging | |||
} | |||
} | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
public void Log(LogSeverity severity, string source, FormattableString message, Exception exception = null) | |||
{ | |||
if (severity <= Level) | |||
@@ -57,7 +57,7 @@ namespace Discord.Logging | |||
public void Debug(string source, Exception ex) | |||
=> Log(LogSeverity.Debug, source, (string)null, ex); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
public void Error(string source, FormattableString message, Exception ex = null) | |||
=> Log(LogSeverity.Error, source, message, ex); | |||
public void Warning(string source, FormattableString message, Exception ex = null) | |||
@@ -38,7 +38,7 @@ namespace Discord.Logging | |||
public void Debug(Exception exception) | |||
=> _manager.Debug(Name, exception); | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
public void Log(LogSeverity severity, FormattableString message, Exception exception = null) | |||
=> _manager.Log(severity, Name, message, exception); | |||
public void Error(FormattableString message, Exception exception = null) | |||
@@ -1,4 +1,4 @@ | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
using Discord.Logging; | |||
using System; | |||
using System.IO; | |||
@@ -1,27 +0,0 @@ | |||
using Discord.ETF; | |||
using System.IO; | |||
using System; | |||
using Discord.Logging; | |||
namespace Discord.Net.Rest | |||
{ | |||
public class ETFRestClient : RestClient | |||
{ | |||
private readonly ETFWriter _serializer; | |||
public ETFRestClient(DiscordConfig config, string baseUrl, ILogger logger = null) | |||
: base(config, baseUrl, logger) | |||
{ | |||
_serializer = new ETFWriter(new MemoryStream()); | |||
} | |||
protected override string Serialize<T>(T obj) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
protected override T Deserialize<T>(string json) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
} |
@@ -36,7 +36,6 @@ namespace Discord.Net.Rest | |||
private readonly DiscordConfig _config; | |||
private readonly IRestEngine _engine; | |||
private readonly ETFWriter _serializer; | |||
private readonly ILogger _logger; | |||
private string _token; | |||
@@ -57,7 +56,7 @@ namespace Discord.Net.Rest | |||
_config = config; | |||
_logger = logger; | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
_engine = new RestSharpEngine(config, baseUrl, logger); | |||
#else | |||
_engine = new BuiltInEngine(config, baseUrl, logger); | |||
@@ -1,4 +1,4 @@ | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
using Discord.Logging; | |||
using Nito.AsyncEx; | |||
using RestSharp; | |||
@@ -1,4 +1,4 @@ | |||
#if DOTNET5_4 | |||
#if NETSTANDARD1_3 | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
@@ -89,7 +89,7 @@ namespace Discord.Net.WebSockets | |||
if (result.MessageType == WebSocketMessageType.Close) | |||
throw new WebSocketException((int)result.CloseStatus.Value, result.CloseStatusDescription); | |||
else | |||
stream.Write(buffer.Array, buffer.Offset, buffer.Count); | |||
stream.Write(buffer.Array, 0, result.Count); | |||
} | |||
while (result == null || !result.EndOfMessage); | |||
@@ -1,4 +1,4 @@ | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
using SuperSocket.ClientEngine; | |||
using System; | |||
using System.Collections.Concurrent; | |||
@@ -49,7 +49,7 @@ namespace Discord.Net.WebSockets | |||
CancelToken = new CancellationToken(true); | |||
_connectedEvent = new ManualResetEventSlim(false); | |||
#if !DOTNET5_4 | |||
#if !NETSTANDARD1_3 | |||
_engine = new WS4NetEngine(config, _taskManager); | |||
#else | |||
_engine = new BuiltInEngine(config); | |||
@@ -1,29 +1,31 @@ | |||
{ | |||
"version": "0.9.1", | |||
"description": "An unofficial .Net API wrapper for the Discord client.", | |||
"authors": [ | |||
"RogueException" | |||
], | |||
"tags": [ | |||
"discord", | |||
"discordapp" | |||
], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
"authors": [ "RogueException" ], | |||
"packOptions": { | |||
"tags": [ | |||
"discord", | |||
"discordapp" | |||
], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
} | |||
}, | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"compilationOptions": { | |||
"buildOptions": { | |||
"compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], | |||
"preserveCompilationContext": true, | |||
"allowUnsafe": true, | |||
"warningsAsErrors": true | |||
}, | |||
"configurations": { | |||
"TestResponses": { | |||
"compilationOptions": { | |||
"buildOptions": { | |||
"define": [ | |||
"DEBUG", | |||
"TRACE", | |||
@@ -34,48 +36,24 @@ | |||
}, | |||
"dependencies": { | |||
"Newtonsoft.Json": "8.0.1", | |||
"Nito.AsyncEx": "3.0.1" | |||
"NETStandard.Library": "1.5.0-rc2-24027", | |||
"Newtonsoft.Json": "8.0.3", | |||
"Nito.AsyncEx": "3.0.1", | |||
"System.Net.Requests": "4.0.11-rc2-24027", | |||
"System.Net.Websockets.Client": "4.0.0-rc2-24027", | |||
"System.Reflection.Emit.Lightweight": "4.0.1-rc2-24027", | |||
"System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027", | |||
"System.Security.Cryptography.Algorithms": "4.1.0-rc2-24027", | |||
"System.Net.NameResolution": "4.0.0-rc2-24027" | |||
}, | |||
"frameworks": { | |||
"dotnet5.4": { | |||
"dependencies": { | |||
"System.Collections": "4.0.11-beta-23516", | |||
"System.Collections.Concurrent": "4.0.11-beta-23516", | |||
"System.Dynamic.Runtime": "4.0.11-beta-23516", | |||
"System.IO.FileSystem": "4.0.1-beta-23516", | |||
"System.IO.Compression": "4.1.0-beta-23516", | |||
"System.Linq": "4.0.1-beta-23516", | |||
"System.Net.Http": "4.0.1-beta-23516", | |||
"System.Net.NameResolution": "4.0.0-beta-23516", | |||
"System.Net.Sockets": "4.1.0-beta-23409", | |||
"System.Net.Requests": "4.0.11-beta-23516", | |||
"System.Net.WebSockets.Client": "4.0.0-beta-23516", | |||
"System.Reflection": "4.1.0-beta-23516", | |||
"System.Reflection.Emit.Lightweight": "4.0.1-beta-23516", | |||
"System.Runtime.InteropServices": "4.0.21-beta-23516", | |||
"System.Runtime.Serialization.Primitives": "4.1.0-beta-23516", | |||
"System.Security.Cryptography.Algorithms": "4.0.0-beta-23516", | |||
"System.Text.RegularExpressions": "4.0.11-beta-23516", | |||
"System.Threading": "4.0.11-beta-23516" | |||
} | |||
}, | |||
"net45": { | |||
"frameworkAssemblies": { | |||
"System.Runtime": { | |||
"type": "build", | |||
"version": "" | |||
}, | |||
"System.Threading.Tasks": { | |||
"type": "build", | |||
"version": "" | |||
} | |||
}, | |||
"dependencies": { | |||
"WebSocket4Net": "0.14.1", | |||
"RestSharp": "105.2.3" | |||
} | |||
"netstandard1.3": { | |||
"imports": [ | |||
"dotnet5.4", | |||
"dnxcore50", | |||
"portable-net45+win8" | |||
] | |||
} | |||
} | |||
} |
@@ -59,14 +59,14 @@ | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\..\src\Discord.Net.Net45\Discord.Net.csproj"> | |||
<Project>{8d71a857-879a-4a10-859e-5ff824ed6688}</Project> | |||
<Name>Discord.Net</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="packages.config" /> | |||
</ItemGroup> | |||
<Choose> | |||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> | |||
<ItemGroup> | |||
@@ -334,7 +334,7 @@ namespace Discord.Tests | |||
async () => await SetGame(_targetBot, "test game"), | |||
x => _observerBot.UserUpdated += x, | |||
x => _observerBot.UserUpdated -= x, | |||
(s, e) => _targetBot.CurrentGame == "test game"); | |||
(s, e) => _targetBot.CurrentGame.Name == "test game"); | |||
} | |||
private async Task SetGame(DiscordClient _client, string game) | |||