You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
12 KiB
246 lines
12 KiB
using System; |
|
using System.Reflection; |
|
using System.Collections.Generic; |
|
|
|
namespace MessagePack.Formatters |
|
{ |
|
public sealed class PrimitiveObjectFormatter : IMessagePackFormatter<object> |
|
{ |
|
public static readonly IMessagePackFormatter<object> Instance = new PrimitiveObjectFormatter(); |
|
|
|
static readonly Dictionary<Type, int> typeToJumpCode = new Dictionary<Type, int>() |
|
{ |
|
{ typeof(Boolean), 0 }, |
|
{ typeof(Char), 1 }, |
|
{ typeof(SByte), 2 }, |
|
{ typeof(Byte), 3 }, |
|
{ typeof(Int16), 4 }, |
|
{ typeof(UInt16), 5 }, |
|
{ typeof(Int32), 6 }, |
|
{ typeof(UInt32), 7 }, |
|
{ typeof(Int64), 8 }, |
|
{ typeof(UInt64),9 }, |
|
{ typeof(Single), 10 }, |
|
{ typeof(Double), 11 }, |
|
{ typeof(DateTime), 12 }, |
|
{ typeof(string), 13 }, |
|
{ typeof(byte[]), 14 } |
|
}; |
|
|
|
PrimitiveObjectFormatter() |
|
{ |
|
|
|
} |
|
|
|
#if !UNITY_WSA |
|
|
|
public static bool IsSupportedType(Type type, TypeInfo typeInfo, object value) |
|
{ |
|
if (value == null) return true; |
|
if (typeToJumpCode.ContainsKey(type)) return true; |
|
if (typeInfo.IsEnum) return true; |
|
|
|
if (value is System.Collections.IDictionary) return true; |
|
if (value is System.Collections.ICollection) return true; |
|
|
|
return false; |
|
} |
|
|
|
#endif |
|
|
|
public int Serialize(ref byte[] bytes, int offset, object value, IFormatterResolver formatterResolver) |
|
{ |
|
if (value == null) |
|
{ |
|
return MessagePackBinary.WriteNil(ref bytes, offset); |
|
} |
|
|
|
var t = value.GetType(); |
|
|
|
int code; |
|
if (typeToJumpCode.TryGetValue(t, out code)) |
|
{ |
|
switch (code) |
|
{ |
|
case 0: |
|
return MessagePackBinary.WriteBoolean(ref bytes, offset, (bool)value); |
|
case 1: |
|
return MessagePackBinary.WriteChar(ref bytes, offset, (char)value); |
|
case 2: |
|
return MessagePackBinary.WriteSByteForceSByteBlock(ref bytes, offset, (sbyte)value); |
|
case 3: |
|
return MessagePackBinary.WriteByteForceByteBlock(ref bytes, offset, (byte)value); |
|
case 4: |
|
return MessagePackBinary.WriteInt16ForceInt16Block(ref bytes, offset, (Int16)value); |
|
case 5: |
|
return MessagePackBinary.WriteUInt16ForceUInt16Block(ref bytes, offset, (UInt16)value); |
|
case 6: |
|
return MessagePackBinary.WriteInt32ForceInt32Block(ref bytes, offset, (Int32)value); |
|
case 7: |
|
return MessagePackBinary.WriteUInt32ForceUInt32Block(ref bytes, offset, (UInt32)value); |
|
case 8: |
|
return MessagePackBinary.WriteInt64ForceInt64Block(ref bytes, offset, (Int64)value); |
|
case 9: |
|
return MessagePackBinary.WriteUInt64ForceUInt64Block(ref bytes, offset, (UInt64)value); |
|
case 10: |
|
return MessagePackBinary.WriteSingle(ref bytes, offset, (Single)value); |
|
case 11: |
|
return MessagePackBinary.WriteDouble(ref bytes, offset, (double)value); |
|
case 12: |
|
return MessagePackBinary.WriteDateTime(ref bytes, offset, (DateTime)value); |
|
case 13: |
|
return MessagePackBinary.WriteString(ref bytes, offset, (string)value); |
|
case 14: |
|
return MessagePackBinary.WriteBytes(ref bytes, offset, (byte[])value); |
|
default: |
|
throw new InvalidOperationException("Not supported primitive object resolver. type:" + t.Name); |
|
} |
|
} |
|
else |
|
{ |
|
#if UNITY_WSA && !NETFX_CORE |
|
if (t.IsEnum) |
|
#else |
|
if (t.GetTypeInfo().IsEnum) |
|
#endif |
|
{ |
|
var underlyingType = Enum.GetUnderlyingType(t); |
|
var code2 = typeToJumpCode[underlyingType]; |
|
switch (code2) |
|
{ |
|
case 2: |
|
return MessagePackBinary.WriteSByteForceSByteBlock(ref bytes, offset, (sbyte)value); |
|
case 3: |
|
return MessagePackBinary.WriteByteForceByteBlock(ref bytes, offset, (byte)value); |
|
case 4: |
|
return MessagePackBinary.WriteInt16ForceInt16Block(ref bytes, offset, (Int16)value); |
|
case 5: |
|
return MessagePackBinary.WriteUInt16ForceUInt16Block(ref bytes, offset, (UInt16)value); |
|
case 6: |
|
return MessagePackBinary.WriteInt32ForceInt32Block(ref bytes, offset, (Int32)value); |
|
case 7: |
|
return MessagePackBinary.WriteUInt32ForceUInt32Block(ref bytes, offset, (UInt32)value); |
|
case 8: |
|
return MessagePackBinary.WriteInt64ForceInt64Block(ref bytes, offset, (Int64)value); |
|
case 9: |
|
return MessagePackBinary.WriteUInt64ForceUInt64Block(ref bytes, offset, (UInt64)value); |
|
default: |
|
break; |
|
} |
|
} |
|
else if (value is System.Collections.IDictionary) // check IDictionary first |
|
{ |
|
var d = value as System.Collections.IDictionary; |
|
var startOffset = offset; |
|
offset += MessagePackBinary.WriteMapHeader(ref bytes, offset, d.Count); |
|
foreach (System.Collections.DictionaryEntry item in d) |
|
{ |
|
offset += Serialize(ref bytes, offset, item.Key, formatterResolver); |
|
offset += Serialize(ref bytes, offset, item.Value, formatterResolver); |
|
} |
|
return offset - startOffset; |
|
} |
|
else if (value is System.Collections.ICollection) |
|
{ |
|
var c = value as System.Collections.ICollection; |
|
var startOffset = offset; |
|
offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, c.Count); |
|
foreach (var item in c) |
|
{ |
|
offset += Serialize(ref bytes, offset, item, formatterResolver); |
|
} |
|
return offset - startOffset; |
|
} |
|
} |
|
|
|
throw new InvalidOperationException("Not supported primitive object resolver. type:" + t.Name); |
|
} |
|
|
|
public object Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) |
|
{ |
|
var type = MessagePackBinary.GetMessagePackType(bytes, offset); |
|
switch (type) |
|
{ |
|
case MessagePackType.Integer: |
|
var code = bytes[offset]; |
|
if (MessagePackCode.MinNegativeFixInt <= code && code <= MessagePackCode.MaxNegativeFixInt) return MessagePackBinary.ReadSByte(bytes, offset, out readSize); |
|
else if (MessagePackCode.MinFixInt <= code && code <= MessagePackCode.MaxFixInt) return MessagePackBinary.ReadByte(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.Int8) return MessagePackBinary.ReadSByte(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.Int16) return MessagePackBinary.ReadInt16(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.Int32) return MessagePackBinary.ReadInt32(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.Int64) return MessagePackBinary.ReadInt64(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.UInt8) return MessagePackBinary.ReadByte(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.UInt16) return MessagePackBinary.ReadUInt16(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.UInt32) return MessagePackBinary.ReadUInt32(bytes, offset, out readSize); |
|
else if (code == MessagePackCode.UInt64) return MessagePackBinary.ReadUInt64(bytes, offset, out readSize); |
|
throw new InvalidOperationException("Invalid primitive bytes."); |
|
case MessagePackType.Boolean: |
|
return MessagePackBinary.ReadBoolean(bytes, offset, out readSize); |
|
case MessagePackType.Float: |
|
if (MessagePackCode.Float32 == bytes[offset]) |
|
{ |
|
return MessagePackBinary.ReadSingle(bytes, offset, out readSize); |
|
} |
|
else |
|
{ |
|
return MessagePackBinary.ReadDouble(bytes, offset, out readSize); |
|
} |
|
case MessagePackType.String: |
|
return MessagePackBinary.ReadString(bytes, offset, out readSize); |
|
case MessagePackType.Binary: |
|
return MessagePackBinary.ReadBytes(bytes, offset, out readSize); |
|
case MessagePackType.Extension: |
|
var ext = MessagePackBinary.ReadExtensionFormatHeader(bytes, offset, out readSize); |
|
if (ext.TypeCode == ReservedMessagePackExtensionTypeCode.DateTime) |
|
{ |
|
return MessagePackBinary.ReadDateTime(bytes, offset, out readSize); |
|
} |
|
throw new InvalidOperationException("Invalid primitive bytes."); |
|
case MessagePackType.Array: |
|
{ |
|
var length = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); |
|
var startOffset = offset; |
|
offset += readSize; |
|
|
|
var objectFormatter = formatterResolver.GetFormatter<object>(); |
|
var array = new object[length]; |
|
for (int i = 0; i < length; i++) |
|
{ |
|
array[i] = objectFormatter.Deserialize(bytes, offset, formatterResolver, out readSize); |
|
offset += readSize; |
|
} |
|
|
|
readSize = offset - startOffset; |
|
return array; |
|
} |
|
case MessagePackType.Map: |
|
{ |
|
var length = MessagePackBinary.ReadMapHeader(bytes, offset, out readSize); |
|
var startOffset = offset; |
|
offset += readSize; |
|
|
|
var objectFormatter = formatterResolver.GetFormatter<object>(); |
|
var hash = new Dictionary<object, object>(length); |
|
for (int i = 0; i < length; i++) |
|
{ |
|
var key = objectFormatter.Deserialize(bytes, offset, formatterResolver, out readSize); |
|
offset += readSize; |
|
|
|
var value = objectFormatter.Deserialize(bytes, offset, formatterResolver, out readSize); |
|
offset += readSize; |
|
|
|
hash.Add(key, value); |
|
} |
|
|
|
readSize = offset - startOffset; |
|
return hash; |
|
} |
|
case MessagePackType.Nil: |
|
readSize = 1; |
|
return null; |
|
default: |
|
throw new InvalidOperationException("Invalid primitive bytes."); |
|
} |
|
} |
|
} |
|
}
|
|
|