// Copyright (c) All contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Buffers; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using MessagePack.Formatters; using UnityEngine; #pragma warning disable SA1402 // multiple types in a file #pragma warning disable SA1649 // file name matches type name namespace MessagePack.Unity.Extension { // use ext instead of ArrayFormatter to extremely boost up performance. // Layout: [extHeader, byteSize(integer), isLittleEndian(bool), bytes()] // Used Ext:30~36 public abstract class UnsafeBlitFormatterBase : IMessagePackFormatter where T : struct { protected abstract sbyte TypeCode { get; } protected void CopyDeserializeUnsafe(ReadOnlySpan src, Span dest) => src.CopyTo(MemoryMarshal.Cast(dest)); public void Serialize(ref MessagePackWriter writer, T[] value, MessagePackSerializerOptions options) { if (value == null) { writer.WriteNil(); return; } var byteLen = value.Length * Marshal.SizeOf(); writer.WriteExtensionFormatHeader(new ExtensionHeader(this.TypeCode, byteLen)); writer.Write(byteLen); // write original header(not array header) writer.Write(BitConverter.IsLittleEndian); writer.WriteRaw(MemoryMarshal.Cast(value)); } public T[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } ExtensionHeader header = reader.ReadExtensionFormatHeader(); if (header.TypeCode != this.TypeCode) { throw new InvalidOperationException("Invalid typeCode."); } var byteLength = reader.ReadInt32(); var isLittleEndian = reader.ReadBoolean(); // Allocate a T[] that we will return. We'll then cast the T[] as byte[] so we can copy the byte sequence directly into it. var result = new T[byteLength / Marshal.SizeOf()]; Span resultAsBytes = MemoryMarshal.Cast(result); reader.ReadRaw(byteLength).CopyTo(resultAsBytes); // Reverse the byte order if necessary. if (isLittleEndian != BitConverter.IsLittleEndian) { for (int i = 0, j = resultAsBytes.Length - 1; i < j; i++, j--) { byte tmp = resultAsBytes[i]; resultAsBytes[i] = resultAsBytes[j]; resultAsBytes[j] = tmp; } } return result; } } public class Vector2ArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityVector2; } } } public class Vector3ArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityVector3; } } } public class Vector4ArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityVector4; } } } public class QuaternionArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityQuaternion; } } } public class ColorArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityColor; } } } public class BoundsArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityBounds; } } } public class RectArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityRect; } } } public class IntArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityInt; } } } public class FloatArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityFloat; } } } public class DoubleArrayBlitFormatter : UnsafeBlitFormatterBase { protected override sbyte TypeCode { get { return ThisLibraryExtensionTypeCodes.UnityDouble; } } } }