| @@ -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" | |||
| ] | |||
| } | |||
| } | |||
| } | |||
| @@ -58,15 +58,15 @@ | |||
| <Compile Include="Tests.cs" /> | |||
| <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) | |||