diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj
index 16b872c78..0dce8fc1c 100644
--- a/src/Discord.Net.Net45/Discord.Net.csproj
+++ b/src/Discord.Net.Net45/Discord.Net.csproj
@@ -421,15 +421,15 @@
Enums\UserStatus.cs
-
- ETF\ETFDecoder.cs
-
-
- ETF\ETFEncoder.cs
+
+ ETF\ETFReader.cs
ETF\ETFType.cs
+
+ ETF\ETFWriter.cs
+
Events\ChannelEventArgs.cs
diff --git a/src/Discord.Net/ETF/ETFEncoder.cs b/src/Discord.Net/ETF/ETFEncoder.cs
deleted file mode 100644
index 060ef3fab..000000000
--- a/src/Discord.Net/ETF/ETFEncoder.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-namespace Discord.ETF
-{
- //TODO: Floats, Atoms, Tuples, Lists, Dictionaries
-
- public unsafe class ETFEncoder
- {
- private readonly static byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' };
- private readonly static byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' };
- private readonly static byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' };
- private byte[] _writeBuffer;
-
- public ETFEncoder()
- {
- _writeBuffer = new byte[11];
- }
-
- private void WriteNil(BinaryWriter writer) => Append(writer, _nilBytes);
- public void Write(BinaryWriter writer, bool value) => Append(writer, value ? _trueBytes : _falseBytes);
-
- public void Write(BinaryWriter writer, byte value) => Write(writer, (ulong)value);
- public void Write(BinaryWriter writer, sbyte value) => Write(writer, (long)value);
- public void Write(BinaryWriter writer, ushort value) => Write(writer, (ulong)value);
- public void Write(BinaryWriter writer, short value) => Write(writer, (long)value);
- public void Write(BinaryWriter writer, uint value) => Write(writer, (ulong)value);
- public void Write(BinaryWriter writer, int value) => Write(writer, (long)value);
- public void Write(BinaryWriter writer, ulong value)
- {
- if (value <= byte.MaxValue)
- Append(writer, new byte[] { (byte)ETFType.SMALL_INTEGER_EXT, (byte)value });
- else if (value <= int.MaxValue)
- {
- Append(writer, (byte)ETFType.INTEGER_EXT,
- (byte)((value >> 24) & 0xFF),
- (byte)((value >> 16) & 0xFF),
- (byte)((value >> 8) & 0xFF),
- (byte)(value & 0xFF));
- }
- else
- {
- var buffer = new byte[3 + 8];
- buffer[0] = (byte)ETFType.SMALL_BIG_EXT;
- //buffer[1] = 0; //Always positive
-
- byte bytes = 0;
- while (value > 0)
- {
- buffer[3 + bytes] = (byte)(value & 0xFF);
- value >>= 8;
- bytes++;
- }
- buffer[1] = bytes; //Encoded bytes
-
- Append(writer, buffer, 3 + bytes);
- }
- }
- public void Write(BinaryWriter writer, long value)
- {
- if (value >= byte.MinValue && value <= byte.MaxValue)
- {
- Append(writer, (byte)ETFType.SMALL_INTEGER_EXT,
- (byte)value);
- }
- else if (value >= int.MinValue && value <= int.MaxValue)
- {
- Append(writer, (byte)ETFType.INTEGER_EXT,
- (byte)((value >> 24) & 0xFF),
- (byte)((value >> 16) & 0xFF),
- (byte)((value >> 8) & 0xFF),
- (byte)(value & 0xFF));
- }
- else
- {
- var buffer = new byte[3 + 8];
- 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 & 0xFF);
- value >>= 8;
- bytes++;
- }
- buffer[1] = bytes; //Encoded bytes
-
- Append(writer, buffer, 3 + bytes);
- }
- }
-
- public void Write(BinaryWriter writer, float value) => Write(writer, (double)value);
- public void Write(BinaryWriter writer, double value)
- {
- ulong value2 = *(ulong*)&value;
- Append(writer, (byte)ETFType.NEW_FLOAT_EXT,
- (byte)((value2 >> 56) & 0xFF),
- (byte)((value2 >> 48) & 0xFF),
- (byte)((value2 >> 40) & 0xFF),
- (byte)((value2 >> 32) & 0xFF),
- (byte)((value2 >> 24) & 0xFF),
- (byte)((value2 >> 16) & 0xFF),
- (byte)((value2 >> 8) & 0xFF),
- (byte)(value2 & 0xFF));
- }
-
- public void Write(BinaryWriter writer, byte[] value)
- {
- int count = value.Length;
- Append(writer, (byte)ETFType.BINARY_EXT,
- (byte)((count >> 24) & 0xFF),
- (byte)((count >> 16) & 0xFF),
- (byte)((count >> 8) & 0xFF),
- (byte)(count & 0xFF));
- Append(writer, value);
- }
- public void Write(BinaryWriter writer, string value)
- {
- throw new NotImplementedException();
- }
-
- /*public void Write(BinaryWriter writer, T value)
- where T : ISerializable
- {
- throw new NotImplementedException();
- }
- public void Write(BinaryWriter writer, IEnumerable value)
- where T : ISerializable
- {
- throw new NotImplementedException();
- }*/
-
- private void Append(BinaryWriter writer, params byte[] data) => Append(writer, data, data.Length);
- private void Append(BinaryWriter writer, byte[] data, int length)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/src/Discord.Net/ETF/ETFDecoder.cs b/src/Discord.Net/ETF/ETFReader.cs
similarity index 72%
rename from src/Discord.Net/ETF/ETFDecoder.cs
rename to src/Discord.Net/ETF/ETFReader.cs
index 760ae20e1..d2f33dcbc 100644
--- a/src/Discord.Net/ETF/ETFDecoder.cs
+++ b/src/Discord.Net/ETF/ETFReader.cs
@@ -3,7 +3,7 @@ using System.IO;
namespace Discord.ETF
{
- public class ETFDecoder
+ public class ETFReader
{
}
}
diff --git a/src/Discord.Net/ETF/ETFWriter.cs b/src/Discord.Net/ETF/ETFWriter.cs
new file mode 100644
index 000000000..06641e664
--- /dev/null
+++ b/src/Discord.Net/ETF/ETFWriter.cs
@@ -0,0 +1,425 @@
+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 readonly static byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' };
+ private readonly static byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' };
+ private readonly static byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' };
+
+ private readonly static MethodInfo _writeTMethod = typeof(ETFWriter).GetTypeInfo()
+ .GetDeclaredMethods(nameof(Write))
+ .Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0])
+ .Single();
+ private readonly static MethodInfo _writeNullableTMethod = 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() == typeof(Nullable<>);
+ })
+ .Single();
+ private readonly static 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 ConcurrentDictionary _serializers, _indirectSerializers;
+
+ public virtual Stream BaseStream
+ {
+ get
+ {
+ Flush();
+ return _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;
+ _serializers = new ConcurrentDictionary();
+ _indirectSerializers = new ConcurrentDictionary();
+ }
+
+ enum EnumTest1 { A, B, C }
+ public static byte[] Test()
+ {
+ using (var stream = new MemoryStream())
+ {
+ using (var writer = new ETFWriter(stream))
+ {
+ var request = new API.Client.Rest.SendMessageRequest(109384029348)
+ {
+ Content = "TestMsg",
+ Nonce = null,
+ IsTTS = false
+ };
+ writer.Write(request);
+ /*writer.Write((EnumTest1?)EnumTest1.C);
+ writer.Write((object)(EnumTest1?)EnumTest1.C);
+ writer.Write((EnumTest1?)null);
+ writer.Write((object)(EnumTest1?)null);*/
+ }
+ return stream.ToArray();
+ }
+ }
+
+ 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)
+ {
+ _buffer[0] = (byte)ETFType.INTEGER_EXT;
+ _buffer[1] = (byte)((value >> 24) & 0xFF);
+ _buffer[2] = (byte)((value >> 16) & 0xFF);
+ _buffer[3] = (byte)((value >> 8) & 0xFF);
+ _buffer[4] = (byte)(value & 0xFF);
+ _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) & 0xFF);
+ _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) & 0xFF);
+ _buffer[2] = (byte)((value >> 16) & 0xFF);
+ _buffer[3] = (byte)((value >> 8) & 0xFF);
+ _buffer[4] = (byte)(value & 0xFF);
+ _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) & 0xFF);
+ _buffer[1] = bytes; //Encoded 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) & 0xFF);
+ _buffer[2] = (byte)((value2 >> 48) & 0xFF);
+ _buffer[3] = (byte)((value2 >> 40) & 0xFF);
+ _buffer[4] = (byte)((value2 >> 32) & 0xFF);
+ _buffer[5] = (byte)((value2 >> 24) & 0xFF);
+ _buffer[6] = (byte)((value2 >> 16) & 0xFF);
+ _buffer[7] = (byte)((value2 >> 8) & 0xFF);
+ _buffer[8] = (byte)(value2 & 0xFF);
+ _stream.Write(_buffer, 0, 9);
+ }
+
+ public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerMillisecond));
+
+ public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); }
+ public void Write(sbyte? 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(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); }
+ public void Write(uint? 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(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
+ public void Write(long? 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(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); }
+ public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); 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) & 0xFF);
+ _buffer[2] = (byte)((count >> 16) & 0xFF);
+ _buffer[3] = (byte)((count >> 8) & 0xFF);
+ _buffer[4] = (byte)(count & 0xFF);
+ _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) & 0xFF);
+ _buffer[2] = (byte)((count >> 16) & 0xFF);
+ _buffer[3] = (byte)((count >> 8) & 0xFF);
+ _buffer[4] = (byte)(count & 0xFF);
+ _stream.Write(_buffer, 0, 5);
+ _stream.Write(bytes, 0, bytes.Length);
+ }
+ else
+ WriteNil();
+ }
+
+ public void Write(T obj)
+ {
+ var type = typeof(T);
+ var typeInfo = type.GetTypeInfo();
+ var action = _serializers.GetOrAdd(type, _ => CreateSerializer(type, typeInfo, false)) as Action;
+ action(this, obj);
+ }
+ public void Write(T? obj)
+ where T : struct
+ {
+ if (obj != null)
+ Write(obj.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