using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Burst;
using Unity.Burst.CompilerServices;
using Unity.Jobs;
using Unity.Jobs.LowLevel.Unsafe;
using Unity.Mathematics;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Unity.Collections
{
    /// 
    /// For scheduling release of unmanaged resources.
    /// 
    public interface INativeDisposable : IDisposable
    {
        /// 
        /// Creates and schedules a job that will release all resources (memory and safety handles) of this collection.
        /// 
        /// A job handle which the newly scheduled job will depend upon.
        /// The handle of a new job that will release all resources (memory and safety handles) of this collection.
        JobHandle Dispose(JobHandle inputDeps);
    }
    /// 
    /// Provides helper methods for collections.
    /// 
    [GenerateTestsForBurstCompatibility]
    public static class CollectionHelper
    {
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        internal static void CheckAllocator(AllocatorManager.AllocatorHandle allocator)
        {
            if (!ShouldDeallocate(allocator))
                throw new ArgumentException($"Allocator {allocator} must not be None or Invalid");
        }
        /// 
        /// The size in bytes of the current platform's L1 cache lines.
        /// 
        /// The size in bytes of the current platform's L1 cache lines.
        public const int CacheLineSize = JobsUtility.CacheLineSize;
        [StructLayout(LayoutKind.Explicit)]
        internal struct LongDoubleUnion
        {
            [FieldOffset(0)]
            internal long longValue;
            [FieldOffset(0)]
            internal double doubleValue;
        }
        /// 
        /// Returns the binary logarithm of the `value`, but the result is rounded down to the nearest integer.
        /// 
        /// The value.
        /// The binary logarithm of the `value`, but the result is rounded down to the nearest integer.
        public static int Log2Floor(int value)
        {
            return 31 - math.lzcnt((uint)value);
        }
        /// 
        /// Returns the binary logarithm of the `value`, but the result is rounded up to the nearest integer.
        /// 
        /// The value.
        /// The binary logarithm of the `value`, but the result is rounded up to the nearest integer.
        public static int Log2Ceil(int value)
        {
            return 32 - math.lzcnt((uint)value - 1);
        }
        /// 
        /// Returns an allocation size in bytes that factors in alignment.
        /// 
        /// 
        /// // 55 aligned to 16 is 64.
        /// int size = CollectionHelper.Align(55, 16);
        /// 
        /// The size to align.
        /// A non-zero, positive power of two.
        /// The smallest integer that is greater than or equal to and is a multiple of .
        /// Thrown if  is not a non-zero, positive power of two.
        public static int Align(int size, int alignmentPowerOfTwo)
        {
            if (alignmentPowerOfTwo == 0)
                return size;
            CheckIntPositivePowerOfTwo(alignmentPowerOfTwo);
            return (size + alignmentPowerOfTwo - 1) & ~(alignmentPowerOfTwo - 1);
        }
        /// 
        /// Returns an allocation size in bytes that factors in alignment.
        /// 
        /// 
        /// // 55 aligned to 16 is 64.
        /// ulong size = CollectionHelper.Align(55, 16);
        /// 
        /// The size to align.
        /// A non-zero, positive power of two.
        /// The smallest integer that is greater than or equal to  and is a multiple of .
        /// Thrown if  is not a non-zero, positive power of two.
        public static ulong Align(ulong size, ulong alignmentPowerOfTwo)
        {
            if (alignmentPowerOfTwo == 0)
                return size;
            CheckUlongPositivePowerOfTwo(alignmentPowerOfTwo);
            return (size + alignmentPowerOfTwo - 1) & ~(alignmentPowerOfTwo - 1);
        }
        /// 
        /// Returns a pointer whose value is rounded up to an address aligned to the provided alignment.
        /// 
        /// 
        /// // 0x80BD5162 aligned to 8 is 0x80BD5168
        /// void* alignedPtr = CollectionHelper.Align(55, 16);
        /// 
        /// The pointer to align.
        /// A non-zero, positive power of two.
        /// The smallest address that is greater than or equal to  and is a multiple of .
        /// Thrown if  is not a non-zero, positive power of two.
        internal static unsafe void* AlignPointer(void* ptr, int alignmentPowerOfTwo)
        {
            if (alignmentPowerOfTwo == 0)
                return ptr;
            CheckIntPositivePowerOfTwo(alignmentPowerOfTwo);
            var ptrAsNuint = (nuint)ptr;
            var alignmentAsNuint = (nuint)alignmentPowerOfTwo;
            return (void*)( (ptrAsNuint + alignmentAsNuint - 1) & ~(alignmentAsNuint - 1) );
        }
        /// 
        /// Returns true if the address represented by the pointer has a given alignment.
        /// 
        /// The pointer.
        /// A non-zero, positive power of two.
        /// True if the address is a multiple of `alignmentPowerOfTwo`.
        /// Thrown if `alignmentPowerOfTwo` is not a non-zero, positive power of two.
        public static unsafe bool IsAligned(void* p, int alignmentPowerOfTwo)
        {
            CheckIntPositivePowerOfTwo(alignmentPowerOfTwo);
            return ((ulong)p & ((ulong)alignmentPowerOfTwo - 1)) == 0;
        }
        /// 
        /// Returns true if an offset has a given alignment.
        /// 
        /// An offset
        /// A non-zero, positive power of two.
        /// True if the offset is a multiple of `alignmentPowerOfTwo`.
        /// Thrown if `alignmentPowerOfTwo` is not a non-zero, positive power of two.
        public static bool IsAligned(ulong offset, int alignmentPowerOfTwo)
        {
            CheckIntPositivePowerOfTwo(alignmentPowerOfTwo);
            return (offset & ((ulong)alignmentPowerOfTwo - 1)) == 0;
        }
        /// 
        /// Returns true if a positive value is a non-zero power of two.
        /// 
        /// Result is invalid if `value < 0`.
        /// A positive value.
        /// True if the value is a non-zero, positive power of two.
        public static bool IsPowerOfTwo(int value)
        {
            return (value & (value - 1)) == 0;
        }
        /// 
        /// Returns a (non-cryptographic) hash of a memory block.
        /// 
        /// The hash function used is [djb2](http://web.archive.org/web/20190508211657/http://www.cse.yorku.ca/~oz/hash.html).
        /// A buffer.
        /// The number of bytes to hash.
        /// A hash of the bytes.
        public static unsafe uint Hash(void* ptr, int bytes)
        {
            // djb2 - Dan Bernstein hash function
            // http://web.archive.org/web/20190508211657/http://www.cse.yorku.ca/~oz/hash.html
            byte* str = (byte*)ptr;
            ulong hash = 5381;
            while (bytes > 0)
            {
                ulong c = str[--bytes];
                hash = ((hash << 5) + hash) + c;
            }
            return (uint)hash;
        }
        [ExcludeFromBurstCompatTesting("Used only for debugging, and uses managed strings")]
        internal static void WriteLayout(Type type)
        {
            Console.WriteLine($"   Offset | Bytes  | Name     Layout: {0}", type.Name);
            var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (var field in fields)
            {
                Console.WriteLine("   {0, 6} | {1, 6} | {2}"
                    , Marshal.OffsetOf(type, field.Name)
                    , Marshal.SizeOf(field.FieldType)
                    , field.Name
                );
            }
        }
        internal static bool ShouldDeallocate(AllocatorManager.AllocatorHandle allocator)
        {
            // Allocator.Invalid == container is not initialized.
            // Allocator.None    == container is initialized, but container doesn't own data.
            return allocator.ToAllocator > Allocator.None;
        }
        /// 
        /// Tell Burst that an integer can be assumed to map to an always positive value.
        /// 
        /// The integer that is always positive.
        /// Returns `x`, but allows the compiler to assume it is always positive.
        [return: AssumeRange(0, int.MaxValue)]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static int AssumePositive(int value)
        {
            return value;
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", GenericTypeArguments = new[] { typeof(NativeArray) })]
        internal static void CheckIsUnmanaged()
        {
            if (!UnsafeUtility.IsUnmanaged())
            {
                throw new ArgumentException($"{typeof(T)} used in native collection is not blittable or not primitive");
            }
        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", GenericTypeArguments = new[] { typeof(NativeArray) })]
        internal static void InitNativeContainer(AtomicSafetyHandle handle)
        {
            if (UnsafeUtility.IsNativeContainerType())
                AtomicSafetyHandle.SetNestedContainer(handle, true);
        }
#endif
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        internal static void CheckIntPositivePowerOfTwo(int value)
        {
            var valid = (value > 0) && ((value & (value - 1)) == 0);
            if (!valid)
            {
                throw new ArgumentException($"Alignment requested: {value} is not a non-zero, positive power of two.");
            }
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        internal static void CheckUlongPositivePowerOfTwo(ulong value)
        {
            var valid = (value > 0) && ((value & (value - 1)) == 0);
            if (!valid)
            {
                throw new ArgumentException($"Alignment requested: {value} is not a non-zero, positive power of two.");
            }
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static void CheckIndexInRange(int index, int length)
        {
            // This checks both < 0 and >= Length with one comparison
            if ((uint)index >= (uint)length)
                throw new IndexOutOfRangeException($"Index {index} is out of range in container of '{length}' Length.");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        internal static void CheckCapacityInRange(int capacity, int length)
        {
            if (capacity < 0)
                throw new ArgumentOutOfRangeException($"Capacity {capacity} must be positive.");
            if (capacity < length)
                throw new ArgumentOutOfRangeException($"Capacity {capacity} is out of range in container of '{length}' Length.");
        }
        /// 
        /// Create a NativeArray, using a provided allocator that implements IAllocator.
        /// 
        /// The type of the elements.
        /// The type of allocator.
        /// The number of elements to allocate.
        /// The allocator to use.
        /// Options for allocation, such as whether to clear the memory.
        /// Returns the NativeArray that was created.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(AllocatorManager.AllocatorHandle) })]
        public static NativeArray CreateNativeArray(int length, ref U allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
            where T : unmanaged
            where U : unmanaged, AllocatorManager.IAllocator
        {
            NativeArray nativeArray;
            if (!allocator.IsCustomAllocator)
            {
                nativeArray = new NativeArray(length, allocator.ToAllocator, options);
            }
            else
            {
                nativeArray = new NativeArray();
                nativeArray.Initialize(length, ref allocator, options);
            }
            return nativeArray;
        }
        /// 
        /// Create a NativeArray, using a provided AllocatorHandle.
        /// 
        /// The type of the elements.
        /// The number of elements to allocate.
        /// The AllocatorHandle to use.
        /// Options for allocation, such as whether to clear the memory.
        /// Returns the NativeArray that was created.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static NativeArray CreateNativeArray(int length, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
            where T : unmanaged
        {
            NativeArray nativeArray;
            if(!AllocatorManager.IsCustomAllocator(allocator))
            {
                nativeArray = new NativeArray(length, allocator.ToAllocator, options);
            }
            else
            {
                nativeArray = new NativeArray();
                nativeArray.Initialize(length, allocator, options);
            }
            return nativeArray;
        }
        /// 
        /// Create a NativeArray from another NativeArray, using a provided AllocatorHandle.
        /// 
        /// The type of the elements.
        /// The NativeArray to make a copy of.
        /// The AllocatorHandle to use.
        /// Returns the NativeArray that was created.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static NativeArray CreateNativeArray(NativeArray array, AllocatorManager.AllocatorHandle allocator)
            where T : unmanaged
        {
            NativeArray nativeArray;
            if (!AllocatorManager.IsCustomAllocator(allocator))
            {
                nativeArray = new NativeArray(array, allocator.ToAllocator);
            }
            else
            {
                nativeArray = new NativeArray();
                nativeArray.Initialize(array.Length, allocator);
                nativeArray.CopyFrom(array);
            }
            return nativeArray;
        }
        /// 
        /// Create a NativeArray from a managed array, using a provided AllocatorHandle.
        /// 
        /// The type of the elements.
        /// The managed array to make a copy of.
        /// The AllocatorHandle to use.
        /// Returns the NativeArray that was created.
        [ExcludeFromBurstCompatTesting("Managed array")]
        public static NativeArray CreateNativeArray(T[] array, AllocatorManager.AllocatorHandle allocator)
            where T : unmanaged
        {
            NativeArray nativeArray;
            if (!AllocatorManager.IsCustomAllocator(allocator))
            {
                nativeArray = new NativeArray(array, allocator.ToAllocator);
            }
            else
            {
                nativeArray = new NativeArray();
                nativeArray.Initialize(array.Length, allocator);
                nativeArray.CopyFrom(array);
            }
            return nativeArray;
        }
        /// 
        /// Create a NativeArray from a managed array, using a provided Allocator.
        /// 
        /// The type of the elements.
        /// The type of allocator.
        /// The managed array to make a copy of.
        /// The Allocator to use.
        /// Returns the NativeArray that was created.
        [ExcludeFromBurstCompatTesting("Managed array")]
        public static NativeArray CreateNativeArray(T[] array, ref U allocator)
            where T : unmanaged
            where U : unmanaged, AllocatorManager.IAllocator
        {
            NativeArray nativeArray;
            if (!allocator.IsCustomAllocator)
            {
                nativeArray = new NativeArray(array, allocator.ToAllocator);
            }
            else
            {
                nativeArray = new NativeArray();
                nativeArray.Initialize(array.Length, ref allocator);
                nativeArray.CopyFrom(array);
            }
            return nativeArray;
        }
        /// 
        /// Dispose a NativeArray from an AllocatorHandle where it is allocated.
        /// 
        /// The type of the elements.
        /// The NativeArray to make a copy of.
        /// The AllocatorHandle used to allocate the NativeArray.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static void DisposeNativeArray(NativeArray nativeArray, AllocatorManager.AllocatorHandle allocator)
            where T : unmanaged
        {
            nativeArray.DisposeCheckAllocator();
        }
        /// 
        /// Dispose a NativeArray from an AllocatorHandle where it is allocated.
        /// 
        /// The type of the elements.
        /// The NativeArray to be disposed.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static void Dispose(NativeArray nativeArray)
            where T : unmanaged
        {
            nativeArray.DisposeCheckAllocator();
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckConvertArguments(int length) where T : unmanaged
        {
            if (length < 0)
                throw new ArgumentOutOfRangeException(nameof(length), "Length must be >= 0");
            if (!UnsafeUtility.IsUnmanaged())
            {
                throw new InvalidOperationException(
                    $"{typeof(T)} used in NativeArray<{typeof(T)}> must be unmanaged (contain no managed types).");
            }
        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
        static void InitNestedNativeContainer(AtomicSafetyHandle handle)
            where T : unmanaged
        {
            if (UnsafeUtility.IsNativeContainerType())
            {
                AtomicSafetyHandle.SetNestedContainer(handle, true);
            }
        }
#endif
        /// 
        /// Convert existing data into a NativeArray.
        /// 
        /// The type of the elements.
        /// Pointer to the data to be converted.
        /// The count of elements.
        /// The Allocator to use.
        /// Use temporary memory atomic safety handle.
        /// Returns the NativeArray that was created.
        /// The caller is still the owner of the data.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static unsafe NativeArray ConvertExistingDataToNativeArray(void* dataPointer, int length, AllocatorManager.AllocatorHandle allocator, bool setTempMemoryHandle = false)
            where T : unmanaged
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
            CheckConvertArguments(length);
#endif
            NativeArray nativeArray = default;
            nativeArray.m_Buffer = dataPointer;
            nativeArray.m_Length = length;
            if (!allocator.IsCustomAllocator)
            {
                nativeArray.m_AllocatorLabel = allocator.ToAllocator;
            }
            else
            {
                nativeArray.m_AllocatorLabel = Allocator.None;
            }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            nativeArray.m_MinIndex = 0;
            nativeArray.m_MaxIndex = length - 1;
            if (setTempMemoryHandle)
            {
                NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.GetTempMemoryHandle());
            }
#endif
            return nativeArray;
        }
        /// 
        /// Convert NativeList into a NativeArray.
        /// 
        /// The type of the elements.
        /// NativeList to be converted.
        /// The count of elements.
        /// The Allocator to use.
        /// Returns the NativeArray that was created.
        /// There is a caveat if users would like to transfer memory ownership from the NativeList to the converted NativeArray.
        /// NativeList implementation includes two memory allocations, one holds its header, another holds the list data.
        /// After convertion, the converted NativeArray holds the list data and dispose the array only free the list data.
        /// Users need to manually free the list header to avoid memory leaks, for example after convertion call,
        /// AllocatorManager.Free(allocator, nativeList.m_ListData); 
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static unsafe NativeArray ConvertExistingNativeListToNativeArray(ref NativeList nativeList, int length, AllocatorManager.AllocatorHandle allocator)
            where T : unmanaged
        {
            NativeArray nativeArray = ConvertExistingDataToNativeArray(nativeList.GetUnsafePtr(), length, allocator);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            var safetyHandle = NativeListUnsafeUtility.GetAtomicSafetyHandle(ref nativeList);
            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, safetyHandle);
            InitNestedNativeContainer(nativeArray.m_Safety);
#endif
            return nativeArray;
        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)]
        internal static AtomicSafetyHandle GetNativeArraySafetyHandle(ref NativeArray nativeArray)
            where T : unmanaged
        {
            return nativeArray.m_Safety;
        }
#endif
        /// 
        /// Create a NativeParallelMultiHashMap from a managed array, using a provided Allocator.
        /// 
        /// The type of the keys.
        /// The type of the values.
        /// The type of allocator.
        /// The desired capacity of the NativeParallelMultiHashMap.
        /// The Allocator to use.
        /// Returns the NativeParallelMultiHashMap that was created.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(int), typeof(AllocatorManager.AllocatorHandle) })]
        public static NativeParallelMultiHashMap CreateNativeParallelMultiHashMap(int length, ref U allocator)
            where TKey : unmanaged, IEquatable
            where TValue : unmanaged
            where U : unmanaged, AllocatorManager.IAllocator
        {
            var container = new NativeParallelMultiHashMap();
            container.Initialize(length, ref allocator);
            return container;
        }
        /// 
        /// Empty job type used for Burst compilation testing
        /// 
        [BurstCompile]
        public struct DummyJob : IJob
        {
            /// 
            /// Empty job execute function used for Burst compilation testing
            /// 
            public void Execute()
            {
            }
        }
        /// 
        /// Checks that reflection data was properly registered for a job.
        /// 
        /// This should be called before instantiating JobsUtility.JobScheduleParameters in order to report to the user if they need to take action.
        /// The reflection data pointer.
        /// Job type
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS",
            GenericTypeArguments = new[] { typeof(DummyJob) })]
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        public static void CheckReflectionDataCorrect(IntPtr reflectionData)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
            bool burstCompiled = true;
            CheckReflectionDataCorrectInternal(reflectionData, ref burstCompiled);
            if (burstCompiled && reflectionData == IntPtr.Zero)
                throw new InvalidOperationException("Reflection data was not set up by an Initialize() call. For generic job types, please include [assembly: RegisterGenericJobType(typeof(MyJob))] in your source file.");
#endif
        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        /// 
        /// Creates a new AtomicSafetyHandle that is valid until [[CollectionHelper.DisposeSafetyHandle]] is called.
        /// 
        /// The AllocatorHandle to use.
        /// Safety handle.
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS")]
        public static AtomicSafetyHandle CreateSafetyHandle(AllocatorManager.AllocatorHandle allocator)
        {
            if (allocator.IsCustomAllocator)
            {
                return AtomicSafetyHandle.Create();
            }
            return (allocator.ToAllocator == Allocator.Temp) ? AtomicSafetyHandle.GetTempMemoryHandle() : AtomicSafetyHandle.Create();
        }
        /// 
        /// Disposes a previously created AtomicSafetyHandle.
        /// 
        /// Safety handle.
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS")]
        public static void DisposeSafetyHandle(ref AtomicSafetyHandle handle)
        {
            AtomicSafetyHandle.CheckDeallocateAndThrow(handle);
            // If the safety handle is for a temp allocation, create a new safety handle for this instance which can be marked as invalid
            // Setting it to new AtomicSafetyHandle is not enough since the handle needs a valid node pointer in order to give the correct errors
            if (AtomicSafetyHandle.IsTempMemoryHandle(handle))
            {
                int staticSafetyId = handle.staticSafetyId;
                handle = AtomicSafetyHandle.Create();
                handle.staticSafetyId = staticSafetyId;
            }
            AtomicSafetyHandle.Release(handle);
        }
        static unsafe void CreateStaticSafetyIdInternal(ref int id, in FixedString512Bytes name)
        {
            id = AtomicSafetyHandle.NewStaticSafetyId(name.GetUnsafePtr(), name.Length);
        }
        [BurstDiscard]
        static void CreateStaticSafetyIdInternal(ref int id)
        {
            CreateStaticSafetyIdInternal(ref id, typeof(T).ToString());
        }
        /// 
        /// Assigns the provided static safety ID to an [[AtomicSafetyHandle]]. The ID's owner type name and any custom error messages are used by the job debugger when reporting errors involving the target handle.
        /// 
        /// This is preferable to AtomicSafetyHandle.NewStaticSafetyId as it is compatible with burst.
        /// Type of container safety handle refers to.
        /// Safety handle.
        /// The static safety ID to associate with the provided handle. This ID must have been allocated with ::ref::NewStaticSafetyId.
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", GenericTypeArguments = new[] { typeof(NativeArray) })]
        public static void SetStaticSafetyId(ref AtomicSafetyHandle handle, ref int sharedStaticId)
        {
            if (sharedStaticId == 0)
            {
                // This will eventually either work with burst supporting a subset of typeof()
                // or something similar to Burst.BurstRuntime.GetTypeName() will be implemented
                // JIRA issue DOTS-5685
                CreateStaticSafetyIdInternal(ref sharedStaticId);
            }
            AtomicSafetyHandle.SetStaticSafetyId(ref handle, sharedStaticId);
        }
        /// 
        /// Assigns the provided static safety ID to an [[AtomicSafetyHandle]]. The ID's owner type name and any custom error messages are used by the job debugger when reporting errors involving the target handle.
        /// 
        /// This is preferable to AtomicSafetyHandle.NewStaticSafetyId as it is compatible with burst.
        /// Safety handle.
        /// The static safety ID to associate with the provided handle. This ID must have been allocated with ::ref::NewStaticSafetyId.
        /// The name of the resource type.
        [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS")]
        public static unsafe void SetStaticSafetyId(ref AtomicSafetyHandle handle, ref int sharedStaticId, FixedString512Bytes name)
        {
            if (sharedStaticId == 0)
            {
                CreateStaticSafetyIdInternal(ref sharedStaticId, name);
            }
            AtomicSafetyHandle.SetStaticSafetyId(ref handle, sharedStaticId);
        }
#endif
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        [BurstDiscard]
        static void CheckReflectionDataCorrectInternal(IntPtr reflectionData, ref bool burstCompiled)
        {
            if (reflectionData == IntPtr.Zero)
                throw new InvalidOperationException($"Reflection data was not set up by an Initialize() call. For generic job types, please include [assembly: RegisterGenericJobType(typeof({typeof(T)}))] in your source file.");
            burstCompiled = false;
        }
    }
}