From 7cbefe6fa28096792b29e0b7d9acc23a23a5703d Mon Sep 17 00:00:00 2001 From: RogueException Date: Tue, 16 Feb 2016 03:32:47 -0400 Subject: [PATCH] Cleaned up ETFWriter --- src/Discord.Net/ETF/ETFWriter.cs | 57 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/Discord.Net/ETF/ETFWriter.cs b/src/Discord.Net/ETF/ETFWriter.cs index 43255780e..37d1553db 100644 --- a/src/Discord.Net/ETF/ETFWriter.cs +++ b/src/Discord.Net/ETF/ETFWriter.cs @@ -12,21 +12,23 @@ 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 static readonly ConcurrentDictionary _serializers = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _indirectSerializers = new ConcurrentDictionary(); - private readonly static MethodInfo _writeTMethod = GetGenericWriteMethod(null); - private readonly static MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>)); - private readonly static MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>)); - private readonly static MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>)); - private readonly static DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + 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 readonly Stream _stream; private readonly byte[] _buffer; private readonly bool _leaveOpen; private readonly Encoding _encoding; - private readonly ConcurrentDictionary _serializers, _indirectSerializers; public virtual Stream BaseStream { @@ -45,8 +47,6 @@ namespace Discord.ETF _leaveOpen = leaveOpen; _buffer = new byte[11]; _encoding = Encoding.UTF8; - _serializers = new ConcurrentDictionary(); - _indirectSerializers = new ConcurrentDictionary(); } public void Write(bool value) @@ -72,6 +72,7 @@ namespace Discord.ETF } 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); @@ -145,7 +146,7 @@ namespace Discord.ETF public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond)); - public void Write(bool? value) { if (value.HasValue) Write((bool)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(); } @@ -158,35 +159,35 @@ namespace Discord.ETF 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(byte[] value) + public void Write(string value) { if (value != null) { - int count = value.Length; + 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(value, 0, value.Length); + _stream.Write(bytes, 0, bytes.Length); } else WriteNil(); } - public void Write(string value) + public void Write(byte[] value) { if (value != null) { - var bytes = _encoding.GetBytes(value); - int count = bytes.Length; + 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(bytes, 0, bytes.Length); + _stream.Write(value, 0, value.Length); } else WriteNil(); @@ -269,7 +270,7 @@ namespace Discord.ETF public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin); #region Emit - private Action CreateSerializer(Type type, TypeInfo typeInfo, bool isDirect) + private static Action CreateSerializer(Type type, TypeInfo typeInfo, bool isDirect) { var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF", null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true); @@ -291,7 +292,7 @@ namespace Discord.ETF generator.Emit(OpCodes.Ret); return method.CreateDelegate(typeof(Action)) as Action; } - private void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) + private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) { //Convert enum types to their base type if (typeInfo.IsEnum) @@ -335,18 +336,21 @@ namespace Discord.ETF //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<>) && + 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)) { @@ -387,7 +391,6 @@ namespace Discord.ETF generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); } } - //Unsupported (decimal, char) else throw new InvalidOperationException($"Serializing {type.Name} is not supported."); @@ -429,7 +432,7 @@ namespace Discord.ETF { return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write)) .Where(x => x.GetParameters()[0].ParameterType == paramType) - .FirstOrDefault(); + .Single(); } private static MethodInfo GetGenericWriteMethod(Type genericType) {