[
  {
    "path": ".gitattributes",
    "content": "* text eol=crlf"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\r\non:\r\n  push:\r\n    branches: [master]\r\n  pull_request:\r\n    branches: [master]\r\n\r\njobs:\r\n  build:\r\n    name: Test\r\n    runs-on: ${{ matrix.os }}\r\n    strategy:\r\n      fail-fast: false\r\n      matrix:\r\n        build: [linux-debug, linux-release]\r\n        include:\r\n          - build: linux-debug\r\n            os: ubuntu-latest\r\n            config: debug\r\n          - build: linux-release\r\n            os: ubuntu-latest\r\n            config: release\r\n    steps:\r\n    - uses: actions/checkout@v3\r\n    - uses: actions/setup-dotnet@v3\r\n      with:\r\n        dotnet-version: | \r\n          6.0.x\r\n          7.0.x\r\n          8.0.x\r\n    #  workaround for actions/setup-dotnet#155\r\n    - name: Clear package cache\r\n      run: dotnet clean Arch.Extended.sln && dotnet nuget locals all --clear\r\n    - name: Restore packages\r\n      run: dotnet restore Arch.Extended.sln\r\n    - name: Build\r\n      run: dotnet build Arch.Extended.sln -c ${{ matrix.config }} --no-restore -warnaserror\r\n    - name: Test\r\n      run: dotnet test Arch.Extended.sln -c ${{ matrix.config }} -l \"console;verbosity=detailed\"\r\n"
  },
  {
    "path": ".gitignore",
    "content": "dist\r\nbin/\r\nobj/\r\n/packages/\r\nriderModule.iml\r\n/_ReSharper.Caches/\r\n\r\n# Common IntelliJ Platform excludes\r\n\r\n# User specific\r\n**/.idea/**/workspace.xml\r\n**/.idea/**/tasks.xml\r\n**/.idea/shelf/*\r\n**/.idea/dictionaries\r\n**/.idea/httpRequests/\r\n\r\n# Sensitive or high-churn files\r\n**/.idea/**/dataSources/\r\n**/.idea/**/dataSources.ids\r\n**/.idea/**/dataSources.xml\r\n**/.idea/**/dataSources.local.xml\r\n**/.idea/**/sqlDataSources.xml\r\n**/.idea/**/dynamic.xml\r\n\r\n# Rider\r\n# Rider auto-generates .iml files, and contentModel.xml\r\n.idea\r\n**/.idea/**/*.iml\r\n**/.idea/**/contentModel.xml\r\n**/.idea/**/modules.xml\r\n\r\n*.suo\r\n*.user\r\n.vs/\r\n[Bb]in/\r\n[Oo]bj/\r\n_UpgradeReport_Files/\r\n[Pp]ackages/\r\n\r\nThumbs.db\r\nDesktop.ini\r\n.DS_Store\r\nFooter\r\n© 2022 GitHub, Inc.\r\nFooter navigation\r\nTerms\r\n\r\n"
  },
  {
    "path": "Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFramework>netstandard2.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <LangVersion>latest</LangVersion>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <PackageId>Arch.AOT.SourceGenerator</PackageId>\r\n        <Title>Arch.AOT.SourceGenerator</Title>\r\n        <Version>1.0.1</Version>\r\n        <Authors>genaray</Authors>\r\n        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\r\n        <Description>A source generator for arch to support AOT. </Description>\r\n        <PackageReleaseNotes>Updated to Arch 1.7 and up. </PackageReleaseNotes>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <IsPackable>true</IsPackable>\r\n\r\n        <LangVersion>11</LangVersion>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageLicenseUrl></PackageLicenseUrl>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"4.1.0\" PrivateAssets=\"analyzers\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n        <None Include=\"$(OutputPath)\\$(AssemblyName).dll\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.AOT.SourceGenerator/ComponentType.cs",
    "content": "﻿namespace Arch.AOT.SourceGenerator;\r\n\r\n/// <summary>\r\n///     The struct <see cref=\"ComponentType\"/>\r\n///\t\trepresents an Component (Their type with meta data) for use in the generated code.\r\n/// </summary>\r\npublic struct ComponentType\r\n{\r\n\t/// <summary>\r\n\t///     The type name of the component.\r\n\t/// </summary>\r\n\tpublic string TypeName { get; }\r\n\t/// <summary>\r\n\t///     If the component has zero fields.\r\n\t/// </summary>\r\n\tpublic bool IsZeroSize { get; }\r\n\t/// <summary>\r\n\t///     If the component is a value type.\r\n\t/// </summary>\r\n\tpublic bool IsValueType { get; }\r\n\r\n\t/// <summary>\r\n\t///\t\tCreates a new instance of the <see cref=\"ComponentType\"/>.\r\n\t/// </summary>\r\n\t/// <param name=\"typeName\">The type name.</param>\r\n\t/// <param name=\"isZeroSize\">If its zero sized.</param>\r\n\t/// <param name=\"isValueType\">If its a value type.</param>\r\n\tpublic ComponentType(string typeName, bool isZeroSize, bool isValueType)\r\n\t{\r\n\t\tTypeName = typeName;\r\n\t\tIsZeroSize = isZeroSize;\r\n\t\tIsValueType = isValueType;\r\n\t}\r\n}"
  },
  {
    "path": "Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs",
    "content": "﻿using System.Text;\r\n\r\nnamespace Arch.AOT.SourceGenerator.Extensions;\r\n\r\n/// <summary>\r\n///\t\tThe <see cref=\"StringBuilderExtensions\"/> class\r\n///\t\tadds code-generating methods to the string-builder for outsourcing them.\r\n/// </summary>\r\npublic static class StringBuilderExtensions\r\n{\r\n\t/// <summary>\r\n\t///     Appends the component types to the string builder in the form of a generated class.\r\n\t/// </summary>\r\n\t/// <param name=\"sb\">The target string builder.</param>\r\n\t/// <param name=\"componentTypes\">The types to append.</param>\r\n\t/// <returns></returns>\r\n\tpublic static StringBuilder AppendComponentTypes(this StringBuilder sb, IList<ComponentType> componentTypes)\r\n\t{\r\n\t\t// Lists the component registration commands line by line. \r\n\t\tvar components = new StringBuilder();\r\n\t\tforeach (var type in componentTypes)\r\n\t\t{\r\n\t\t\tvar componentType = type;\r\n\t\t\tcomponents.AppendComponentType(ref componentType);\r\n\t\t}\r\n\t\t\r\n\t\tsb.AppendLine(\r\n\t\t\t$$\"\"\"\r\n\t\t    using System.Runtime.CompilerServices;\r\n\t\t    using Arch.Core.Utils;\r\n\t\t              \r\n\t\t    namespace Arch.AOT.SourceGenerator\r\n\t\t    {\r\n\t\t       internal static class GeneratedComponentRegistry\r\n\t\t       {\r\n\t\t          [ModuleInitializer]\r\n\t\t          public static void Initialize()\r\n\t\t          {\r\n\t\t          {{components}}\r\n\t\t          }\r\n\t\t       }\r\n\t\t    }\r\n\t\t    \"\"\"\r\n\t\t);\r\n\t\treturn sb;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t///     Appends a single component type to the string builder as a new line.\r\n\t/// </summary>\r\n\t/// <param name=\"sb\">The string builder.</param>\r\n\t/// <param name=\"componentType\">The component type to add.</param>\r\n\t/// <returns></returns>\r\n\tpublic static StringBuilder AppendComponentType(this StringBuilder sb, ref ComponentType componentType)\r\n\t{\r\n\t\t//var size = componentType.IsValueType ? $\"Unsafe.SizeOf<{componentType.TypeName}>()\" : \"IntPtr.Size\";\r\n\t\t//sb.AppendLine($\"ComponentRegistry.Add(typeof({componentType.TypeName}), new ComponentType(ComponentRegistry.Size + 1, {size}));\");\r\n\t\t\r\n\t\tsb.AppendLine($\"ArrayRegistry.Add<{componentType.TypeName}>();\");\r\n\t\treturn sb;\r\n\t}\r\n}\r\n"
  },
  {
    "path": "Arch.AOT.SourceGenerator/SourceGenerator.cs",
    "content": "﻿using System.Collections.Immutable;\r\nusing System.Text;\r\nusing Arch.AOT.SourceGenerator.Extensions;\r\nusing Microsoft.CodeAnalysis;\r\nusing Microsoft.CodeAnalysis.CSharp;\r\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\r\nusing Microsoft.CodeAnalysis.Text;\r\n\r\nnamespace Arch.AOT.SourceGenerator;\r\n\r\n/// <summary>\r\n///     Incremental generator that generates a class that adds all components to the ComponentRegistry.\r\n/// </summary>\r\n[Generator(LanguageNames.CSharp)]\r\npublic sealed class ComponentRegistryGenerator : IIncrementalGenerator\r\n{\r\n\t/// <summary>\r\n\t///\t\tA <see cref=\"List{T}\"/> of annotated components (their types) found via the source-gen. \r\n\t/// </summary>\r\n\tprivate readonly List<ComponentType> _componentTypes = new();\r\n\t\r\n\t/// <summary>\r\n\t///\t\tThe attribute to mark components with in order to be found by this source-gen. \r\n\t/// </summary>\r\n\tprivate const string AttributeTemplate = \"\"\"\r\n\t                                         using System;\r\n\r\n\t                                         namespace Arch.AOT.SourceGenerator\r\n\t                                         {\r\n\t                                             [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = false, Inherited = false)]\r\n\t                                             public sealed class ComponentAttribute : Attribute { }\r\n\t                                         }\r\n\t                                         \"\"\";\r\n\r\n\t/// <inheritdoc cref=\"IIncrementalGenerator.Initialize\"/>\r\n\tpublic void Initialize(IncrementalGeneratorInitializationContext context)\r\n\t{\r\n\t\t// Register the attribute.\r\n\t\tcontext.RegisterPostInitializationOutput(initializationContext =>\r\n\t\t{\r\n\t\t\tinitializationContext.AddSource(\"Components.Attributes.g.cs\", SourceText.From(AttributeTemplate, Encoding.UTF8));\r\n\t\t});\r\n\r\n\t\tvar provider = context.SyntaxProvider.CreateSyntaxProvider(\r\n\t\t\tShouldTypeBeRegistered,\r\n\t\t\tGetMemberDeclarationsForSourceGen).Where(t => t.attributeFound).Select((t, _) => t.Item1\r\n\t\t);\r\n\r\n\t\tcontext.RegisterSourceOutput(\r\n\t\t\tcontext.CompilationProvider.Combine(provider.Collect()), (productionContext, tuple) => GenerateCode(productionContext, tuple.Left, tuple.Right)\r\n\t\t);\r\n\t}\r\n\r\n\t/// <summary>\r\n\t///     Determines if a node should be considered for code generation.\r\n\t/// </summary>\r\n\t/// <param name=\"node\"></param>\r\n\t/// <param name=\"cancellationToken\"></param>\r\n\t/// <returns></returns>\r\n\tprivate static bool ShouldTypeBeRegistered(SyntaxNode node, CancellationToken cancellationToken)\r\n\t{\r\n\t\tif (node is not TypeDeclarationSyntax typeDeclarationSyntax)\r\n\t\t{\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn typeDeclarationSyntax.AttributeLists.Count != 0;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t///     Make sure the type is annotated with the Component attribute.\r\n\t/// </summary>\r\n\t/// <param name=\"context\"></param>\r\n\t/// <param name=\"cancellationToken\"></param>\r\n\t/// <returns></returns>\r\n\tprivate static (TypeDeclarationSyntax, bool attributeFound) GetMemberDeclarationsForSourceGen(GeneratorSyntaxContext context, CancellationToken cancellationToken)\r\n\t{\r\n\t\tvar typeDeclarationSyntax = (TypeDeclarationSyntax) context.Node;\r\n\r\n\t\t// Stop here if we can't get the type symbol for some reason.\r\n\t\tif (ModelExtensions.GetDeclaredSymbol(context.SemanticModel, typeDeclarationSyntax) is not ITypeSymbol symbol)\r\n\t\t{\r\n\t\t\treturn (typeDeclarationSyntax, false);\r\n\t\t}\r\n\r\n\t\t// Go through all the attributes.\r\n\t\tforeach (var attributeData in symbol.GetAttributes())\r\n\t\t{\r\n\t\t\tif (attributeData.AttributeClass is null)\r\n\t\t\t{\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// If the attribute is the Component attribute, we can stop here and return true.\r\n\t\t\tif (string.Equals(attributeData.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), \"global::Arch.AOT.SourceGenerator.ComponentAttribute\",\r\n\t\t\t\t    StringComparison.Ordinal))\r\n\t\t\t{\r\n\t\t\t\treturn (typeDeclarationSyntax, true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// No attribute found, return false.\r\n\t\treturn (typeDeclarationSyntax, false);\r\n\t}\r\n\r\n\tprivate void GenerateCode(SourceProductionContext productionContext, Compilation compilation, ImmutableArray<TypeDeclarationSyntax> typeList)\r\n\t{\r\n\t\tvar sb = new StringBuilder();\r\n\t\t_componentTypes.Clear();\r\n\r\n\t\tforeach (var type in typeList)\r\n\t\t{\r\n\t\t\t// Get the symbol for the type.\r\n\t\t\tvar symbol = ModelExtensions.GetDeclaredSymbol(compilation.GetSemanticModel(type.SyntaxTree), type);\r\n\r\n\t\t\t// If the symbol is not a type symbol, we can't do anything with it.\r\n\t\t\tif (symbol is not ITypeSymbol typeSymbol)\r\n\t\t\t{\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// Check if there are any fields in the type.\r\n\t\t\tvar hasZeroFields = true;\r\n\t\t\tforeach (var member in typeSymbol.GetMembers())\r\n\t\t\t{\r\n\t\t\t\tif (member is not IFieldSymbol) continue;\r\n\t\t\t\t\r\n\t\t\t\thasZeroFields = false;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tvar typeName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);\r\n\t\t\t_componentTypes.Add(new ComponentType(typeName, hasZeroFields, typeSymbol.IsValueType));\r\n\t\t}\r\n\r\n\t\tsb.AppendComponentTypes(_componentTypes);\r\n\t\tproductionContext.AddSource(\"GeneratedComponentRegistry.g.cs\",CSharpSyntaxTree.ParseText(sb.ToString()).GetRoot().NormalizeWhitespace().ToFullString());\r\n\t}\r\n}"
  },
  {
    "path": "Arch.EventBus/Arch.EventBus.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <TargetFramework>netstandard2.0</TargetFramework>\r\n        <LangVersion>11</LangVersion>\r\n        <RootNamespace>Arch.Bus</RootNamespace>\r\n\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n\r\n        <PackageId>Arch.EventBus</PackageId>\r\n        <Title>Arch.EventBus</Title>\r\n        <Version>1.0.2</Version>\r\n        <Authors>genaray</Authors>\r\n        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\r\n        <Description>A basic EventBus using source generation.</Description>\r\n        <PackageReleaseNotes>Fixed some issues with source generation.\r\n        </PackageReleaseNotes>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <IsPackable>true</IsPackable>\r\n\r\n        <LangVersion>11</LangVersion>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageLicenseUrl></PackageLicenseUrl>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"4.1.0\" PrivateAssets=\"analyzers\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n        <None Include=\"$(OutputPath)\\$(AssemblyName).dll\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.EventBus/EventBus.cs",
    "content": "﻿using System.Text;\r\nusing Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.Bus;\r\n\r\n/// <summary>\r\n///     The EventBus model\r\n/// </summary>\r\npublic struct EventBus\r\n{\r\n    /// <summary>\r\n    ///     The namespace.\r\n    /// </summary>\r\n    public string Namespace { get; set; }\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"Method\"/>s of the <see cref=\"EventBus\"/> \"redirecting\" the event.\r\n    /// </summary>\r\n    public IList<Method> Methods;\r\n}\r\n\r\n/// <summary>\r\n///     A method inside the eventbus redirecting the event towards the receivers. \r\n/// </summary>\r\npublic struct Method\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"RefKind\"/> this method accepts as a param.\r\n    /// </summary>\r\n    public RefKind RefKind;\r\n    \r\n    /// <summary>\r\n    ///     The Event type as a <see cref=\"ITypeSymbol\"/> that is being passed to the method and being redirected.\r\n    /// </summary>\r\n    public ITypeSymbol EventType;\r\n    \r\n    /// <summary>\r\n    ///     A list of methods which this <see cref=\"Method\"/> redirects the event to.\r\n    /// </summary>\r\n    public IList<ReceivingMethod> EventReceivingMethods;\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ReceivingMethod\"/> struct\r\n///     represents a method that receives the event (and is marked by the event tag) with its order. \r\n/// </summary>\r\npublic struct ReceivingMethod\r\n{\r\n\r\n    /// <summary>\r\n    ///     If the receiving method is static.\r\n    ///     If not, we are targeting instances and need to handle them differently during generation. \r\n    /// </summary>\r\n    public bool Static;\r\n    \r\n    /// <summary>\r\n    ///     The method symbol of the static event receiver which should be called.\r\n    /// </summary>\r\n    public IMethodSymbol MethodSymbol;\r\n    \r\n    /// <summary>\r\n    ///     Its order. \r\n    /// </summary>\r\n    public int Order;\r\n}\r\n\r\n/// <summary>\r\n/// EventBusExtensions\r\n/// </summary>\r\npublic static class EventBusExtensions\r\n{\r\n    \r\n        \r\n    /// <summary>\r\n    ///     Convert a <see cref=\"RefKind\"/> to its code string equivalent.\r\n    /// </summary>\r\n    /// <param name=\"refKind\">The <see cref=\"RefKind\"/>.</param>\r\n    /// <returns>The code string equivalent.</returns>\r\n    public static string RefKindToString(RefKind refKind)\r\n    {\r\n        switch (refKind)\r\n        {\r\n            case RefKind.None:\r\n                return \"\";\r\n            case RefKind.Ref:\r\n                return \"ref\";\r\n            case RefKind.In:\r\n                return \"in\";\r\n            case RefKind.Out:\r\n                return \"out\";\r\n        }\r\n        return null!;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Appends all methods redirecting events.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"callMethods\">The <see cref=\"IList{T}\"/> containing the <see cref=\"Method\"/>s redirecting the event and calling the methods. </param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendEventMethods(this StringBuilder sb, IList<Method> callMethods)\r\n    {\r\n        foreach (var eventCallMethod in callMethods)\r\n        {\r\n            sb.AppendEventMethod(eventCallMethod);\r\n        }\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends all methods redirecting events.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"callMethod\">The <see cref=\"IList{T}\"/> containing the <see cref=\"Method\"/>s redirecting the event and calling the methods. </param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendEventMethod(this StringBuilder sb, Method callMethod)\r\n    {\r\n        var callMethodsInOrder = new StringBuilder().MethodCalls(callMethod);\r\n        var instanceReceiverLists = new StringBuilder().InstanceReceiverLists(callMethod);\r\n        \r\n        var template = $$\"\"\"\r\n        {{instanceReceiverLists}}\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void Send({{RefKindToString(callMethod.RefKind)}} {{callMethod.EventType.ToDisplayString()}} {{callMethod.EventType.Name.ToLower()}}){\r\n            {{callMethodsInOrder}}\r\n        }\r\n        \"\"\";\r\n        sb.AppendLine(template);\r\n        return sb;\r\n    }\r\n    \r\n    \r\n    /// <summary>\r\n    ///     Appends calls to all event receiving method.\r\n    ///     <remarks>SomeMethod(...); OtherMethod(...); ...</remarks>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"callMethod\">The <see cref=\"Method\"/> the event call which methods will be called after one another.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder MethodCalls(this StringBuilder sb, Method callMethod)\r\n    {\r\n        // Loop over every found method receiver\r\n        foreach (var eventReceivingMethod in callMethod.EventReceivingMethods)\r\n        {\r\n            var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;\r\n            var methodName = eventReceivingMethod.MethodSymbol.Name;\r\n            var passEvent = $\"{RefKindToString(callMethod.RefKind)} {callMethod.EventType.Name.ToLower()}\";\r\n            \r\n            // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything\r\n            var eventType = callMethod.EventType.ToString();\r\n            eventType = eventType.Replace(\"(\",\"\").Replace(\")\",\"\").Replace(\".\",\"_\").Replace(\",\",\"_\").Replace(\" \",\"\");\r\n            \r\n            // If static, call directly... if non static, loop over the instances for this event and call them one by one.\r\n            if (eventReceivingMethod.Static)\r\n            {\r\n                sb.AppendLine($\"{containingSymbol}.{methodName}({passEvent});\");   \r\n            }\r\n            else\r\n            {\r\n                var instanceList = $\"{containingSymbol.Name}_{methodName}_{eventType}\";\r\n                var template = $$\"\"\"\r\n                    for(var index = 0; index < {{instanceList}}.Count; index++)\r\n                    {\r\n                        {{instanceList}}[index].{{methodName}}({{passEvent}});\r\n                    }\r\n                \"\"\";\r\n                sb.AppendLine(template);\r\n            }\r\n        }\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends lists for a certain <see cref=\"Method\"/> containing one list for each instance (non static) receiving a method.\r\n    ///     <remarks>List&lt;SomeInstance&gt; SomeInstance_OnSomeEvent_EventType; ...</remarks>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"callMethod\">The <see cref=\"Method\"/> the event call which methods will be called after one another.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder InstanceReceiverLists(this StringBuilder sb, Method callMethod)\r\n    {\r\n        foreach (var eventReceivingMethod in callMethod.EventReceivingMethods)\r\n        {\r\n            var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;\r\n            var methodName = eventReceivingMethod.MethodSymbol.Name;\r\n            \r\n            // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything\r\n            var eventType = callMethod.EventType.ToString();\r\n            eventType = eventType.Replace(\"(\",\"\").Replace(\")\",\"\").Replace(\".\",\"_\").Replace(\",\",\"_\").Replace(\" \",\"\");\r\n            \r\n            if (eventReceivingMethod.Static)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            sb.AppendLine($\"public static List<{containingSymbol}> {containingSymbol.Name}_{methodName}_{eventType} = new List<{containingSymbol}>(128);\");\r\n        }\r\n        return sb;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Appends a <see cref=\"EventBus\"/> and generates it.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"eventBus\">The <see cref=\"EventBus\"/> itself, used to generate the EventBus in code.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendEventBus(this StringBuilder sb, ref EventBus eventBus)\r\n    {\r\n        var callerMethods = new StringBuilder().AppendEventMethods(eventBus.Methods);\r\n        var template = $$\"\"\"\r\n        using System.Runtime.CompilerServices;\r\n        using System.Collections.Generic;\r\n        namespace {{eventBus.Namespace}}{\r\n            public partial class EventBus{\r\n                {{callerMethods}}\r\n            }\r\n        }\r\n        \"\"\";\r\n        return sb.Append(template);\r\n    }\r\n}"
  },
  {
    "path": "Arch.EventBus/Hooks.cs",
    "content": "﻿using System.Text;\r\nusing Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.Bus;\r\n\r\n/// <summary>\r\n/// Hooks.\r\n/// </summary>\r\npublic struct Hooks\r\n{\r\n    /// <summary>\r\n    /// Instances.\r\n    /// </summary>\r\n    public List<ClassHooks> Instances;\r\n}\r\n\r\n/// <summary>\r\n/// Class hooks.\r\n/// </summary>\r\npublic struct ClassHooks\r\n{\r\n    /// <summary>\r\n    /// Partial class.\r\n    /// </summary>\r\n    public ITypeSymbol PartialClass;\r\n\r\n    /// <summary>\r\n    /// Event hooks.\r\n    /// </summary>\r\n    public IList<EventHook> EventHooks;\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"EventHook\"/> struct\r\n///     represents a hook for an event from the eventbus inside an class instance.\r\n/// </summary>\r\npublic struct EventHook\r\n{\r\n\r\n    /// <summary>\r\n    ///     The event type.\r\n    /// </summary>\r\n    public ITypeSymbol EventType;\r\n    \r\n    /// <summary>\r\n    ///     The method symbol of the static event receiver which should be called.\r\n    /// </summary>\r\n    public IMethodSymbol MethodSymbol;\r\n}\r\n\r\n/// <summary>\r\n/// Hook extensions.\r\n/// </summary>\r\npublic static class HookExtensions\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Appends add operations for a set of <see cref=\"EventHook\"/> to hook the local class instance into the EventBus instance lists for receiving events. \r\n    ///     <remarks>EventBus.SomeClass_SomeEvent_SomeEvent.Add(this); ...</remarks>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"receivingMethods\">The <see cref=\"List{T}\"/> of <see cref=\"ReceivingMethod\"/> that will be hooked in to receive instance events. </param>\r\n    /// <returns></returns>\r\n    public static StringBuilder Hook(this StringBuilder sb, IList<EventHook> receivingMethods)\r\n    {\r\n        foreach (var eventReceivingMethod in receivingMethods)\r\n        {\r\n            var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;\r\n            var methodName = eventReceivingMethod.MethodSymbol.Name;\r\n            \r\n            // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything\r\n            var eventType = eventReceivingMethod.EventType.ToString();\r\n            eventType = eventType.Replace(\"(\",\"\").Replace(\")\",\"\").Replace(\".\",\"_\").Replace(\",\",\"_\").Replace(\" \",\"\");\r\n\r\n            sb.AppendLine($\"EventBus.{containingSymbol.Name}_{methodName}_{eventType}.Add(this);\");\r\n        }\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends remove operations for a set of <see cref=\"EventHook\"/> to unhook the local class instance from the EventBus instance lists for receiving events. \r\n    ///     <remarks>EventBus.SomeClass_SomeEvent_SomeEvent.Remove(this); ...</remarks>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"receivingMethods\">The <see cref=\"List{T}\"/> of <see cref=\"ReceivingMethod\"/> that will be hooked in to receive instance events. </param>\r\n    /// <returns></returns>\r\n    public static StringBuilder Unhook(this StringBuilder sb, IList<EventHook> receivingMethods)\r\n    {\r\n        foreach (var eventReceivingMethod in receivingMethods)\r\n        {\r\n            var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;\r\n            var methodName = eventReceivingMethod.MethodSymbol.Name;\r\n            \r\n            // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything\r\n            var eventType = eventReceivingMethod.EventType.ToString();\r\n            eventType = eventType.Replace(\"(\",\"\").Replace(\")\",\"\").Replace(\".\",\"_\").Replace(\",\",\"_\").Replace(\" \",\"\");\r\n            \r\n            sb.AppendLine($\"EventBus.{containingSymbol.Name}_{methodName}_{eventType}.Remove(this);\");\r\n        }\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends a <see cref=\"List{T}\"/> of <see cref=\"Hook\"/> and generates proper hook and unhook methods for their partial class instances.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"hooks\">The <see cref=\"List{T}\"/> of <see cref=\"Hook\"/> itself, used to generate the hooks in code.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendHookList(this StringBuilder sb, List<ClassHooks> hooks)\r\n    {\r\n        // Loop over all hooks to create the hook and unhook functions.\r\n        foreach (var hook in hooks)\r\n        {\r\n\r\n            var hookIntoEventbus = new StringBuilder().Hook(hook.EventHooks);\r\n            var unhookFromEventBus = new StringBuilder().Unhook(hook.EventHooks);\r\n            \r\n            var template = $$\"\"\"\r\n            namespace {{hook.PartialClass.ContainingNamespace}}{\r\n\r\n                public partial class {{hook.PartialClass.Name}}{\r\n                    \r\n                    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n                    public void Hook()\r\n                    {\r\n                        {{hookIntoEventbus}}\r\n                    }\r\n                    \r\n                    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n                    public void Unhook()\r\n                    {\r\n                        {{unhookFromEventBus}}   \r\n                    }\r\n                }\r\n            }\r\n            \"\"\";\r\n            sb.AppendLine(template);\r\n        }\r\n\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends a <see cref=\"Hooks\"/> and generates it.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"hooks\">The <see cref=\"Hooks\"/> itself, used to generate the hooks in code.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendHooks(this StringBuilder sb, ref Hooks hooks)\r\n    {\r\n        var callerMethods = new StringBuilder().AppendHookList(hooks.Instances);\r\n        var template = $$\"\"\"\r\n        using System.Runtime.CompilerServices;\r\n        using Arch.Bus;\r\n        {{callerMethods}}\r\n        \"\"\";\r\n        return sb.Append(template);\r\n    }\r\n}"
  },
  {
    "path": "Arch.EventBus/MethodSymbolExtensions.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.Bus;\r\n\r\n/// <summary>\r\n/// Method symbol extensions.\r\n/// </summary>\r\npublic static class MethodSymbolExtensions\r\n{\r\n\r\n    /// <summary>\r\n    ///     Searches attributes of a <see cref=\"IMethodSymbol\"/> and returns the first one found.\r\n    /// </summary>\r\n    /// <param name=\"ms\">The <see cref=\"IMethodSymbol\"/> instance.</param>\r\n    /// <param name=\"name\">The attributes name.</param>\r\n    /// <returns>The attribute wrapped in an <see cref=\"AttributeData\"/>.</returns>\r\n    public static AttributeData GetAttributeData(this IMethodSymbol ms, string name)\r\n    {\r\n        foreach (var attribute in ms.GetAttributes())\r\n        {\r\n            var classSymbol = attribute.AttributeClass;\r\n            if(!classSymbol!.Name.Contains(name)) continue;\r\n\r\n            return attribute;\r\n        }\r\n\r\n        return default!;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Gets all the types of a <see cref=\"AttributeData\"/> as <see cref=\"ITypeSymbol\"/>s and adds them to a list.\r\n    ///     If the attribute is generic it will add the generic parameters, if its non generic it will add the non generic types from the constructor.\r\n    /// </summary>\r\n    /// <param name=\"data\">The <see cref=\"AttributeData\"/>.</param>\r\n    /// <param name=\"array\">The <see cref=\"List{T}\"/> where the found <see cref=\"ITypeSymbol\"/>s are added to.</param>\r\n    public static void GetAttributeTypes(this AttributeData? data, List<ITypeSymbol> array)\r\n    {\r\n        if (data is not null && data.AttributeClass!.IsGenericType)\r\n        {\r\n            array.AddRange(data.AttributeClass.TypeArguments);\r\n        }\r\n        else if (data is not null && !data.AttributeClass!.IsGenericType)\r\n        {\r\n            var constructorArguments = data.ConstructorArguments[0].Values;\r\n            var constructorArgumentsTypes = constructorArguments.Select(constant => constant.Value as ITypeSymbol).ToList();\r\n            array.AddRange(constructorArgumentsTypes!);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.EventBus/SourceGenerator.cs",
    "content": "﻿using System.Collections.Immutable;\r\nusing System.Diagnostics;\r\nusing System.Text;\r\nusing Microsoft.CodeAnalysis;\r\nusing Microsoft.CodeAnalysis.CSharp;\r\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\r\nusing Microsoft.CodeAnalysis.Text;\r\n\r\nnamespace Arch.Bus;\r\n\r\n/// <summary>\r\n/// Query generator.\r\n/// </summary>\r\n[Generator]\r\npublic class QueryGenerator : IIncrementalGenerator\r\n{\r\n    private static EventBus _eventBus;\r\n    private static Hooks _hooks;\r\n    \r\n    private static Dictionary<ITypeSymbol, (RefKind, IList<ReceivingMethod>)> _eventTypeToReceivingMethods = null!;\r\n    private static Dictionary<ITypeSymbol, IList<EventHook>> _containingTypeToReceivingMethods = null!;\r\n\r\n    /// <inheritdoc cref=\"IIncrementalGenerator.Initialize\"/>\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        //if (!Debugger.IsAttached) Debugger.Launch();\r\n\r\n        // Register the generic attributes \r\n        var attributes = $$\"\"\"\r\n            namespace Arch.Bus\r\n            {           \r\n                /// <summary>\r\n                ///     Marks a method to receive a certain event. \r\n                /// </summary>\r\n                [global::System.AttributeUsage(global::System.AttributeTargets.Method)]\r\n                public class EventAttribute : global::System.Attribute\r\n                {\r\n                    public EventAttribute(int order = 0)\r\n                    {\r\n                        Order = order;\r\n                    }\r\n\r\n                    /// <summary>\r\n                    /// The order of this event. \r\n                    /// </summary>\r\n                    public int Order { get; }\r\n                }\r\n            }\r\n        \"\"\";\r\n        context.RegisterPostInitializationOutput(ctx => ctx.AddSource(\"Attributes.g.cs\", SourceText.From(attributes, Encoding.UTF8)));\r\n\r\n        // Do a simple filter for methods marked with update\r\n        IncrementalValuesProvider<MethodDeclarationSyntax> methodDeclarations = context.SyntaxProvider.CreateSyntaxProvider(\r\n            static (s, _) => s is MethodDeclarationSyntax { AttributeLists.Count: > 0 },\r\n            static (ctx, _) => GetMethodSymbolIfAttributeof(ctx, \"Arch.Bus.EventAttribute\")\r\n        ).Where(static m => m is not null)!; // filter out attributed methods that we don't care about\r\n        \r\n        // Combine the selected enums with the `Compilation`\r\n        IncrementalValueProvider<(Compilation, ImmutableArray<MethodDeclarationSyntax>)> compilationAndMethods =\r\n            context.CompilationProvider.Combine(methodDeclarations.WithComparer(Comparer.Instance).Collect());\r\n        context.RegisterSourceOutput(compilationAndMethods, static (spc, source) => Generate(source.Item1, source.Item2, spc));\r\n    }\r\n    \r\n\r\n    /// <summary>\r\n    ///     Returns a <see cref=\"MethodDeclarationSyntax\"/> if its annotated with an attribute of <paramref name=\"name\"/>.\r\n    /// </summary>\r\n    /// <param name=\"context\">Its <see cref=\"GeneratorSyntaxContext\"/>.</param>\r\n    /// <param name=\"name\">The attributes name.</param>\r\n    /// <returns></returns>\r\n    private static MethodDeclarationSyntax? GetMethodSymbolIfAttributeof(GeneratorSyntaxContext context, string name)\r\n    {\r\n        // we know the node is a EnumDeclarationSyntax thanks to IsSyntaxTargetForGeneration\r\n        var methodDeclarationSyntax = (MethodDeclarationSyntax)context.Node;\r\n\r\n        // loop through all the attributes on the method\r\n        foreach (var attributeListSyntax in methodDeclarationSyntax.AttributeLists)\r\n        {\r\n            foreach (var attributeSyntax in attributeListSyntax.Attributes)\r\n            {\r\n                if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) continue;\r\n\r\n                var attributeContainingTypeSymbol = attributeSymbol.ContainingType;\r\n                var fullName = attributeContainingTypeSymbol.ToDisplayString();\r\n\r\n                // Is the attribute the [EnumExtensions] attribute?\r\n                if (fullName != name) continue;\r\n                return methodDeclarationSyntax;\r\n            }\r\n        }\r\n\r\n        // we didn't find the attribute we were looking for\r\n        return null;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Maps the <see cref=\"IMethodSymbol\"/> to its <see cref=\"IParameterSymbol\"/> for organisation. \r\n    /// </summary>\r\n    /// <param name=\"methodSymbol\"></param>\r\n    private static void MapMethodToEventType(IMethodSymbol methodSymbol)\r\n    {\r\n        var eventType = methodSymbol.Parameters[0];\r\n        var param = methodSymbol.GetAttributes()[0].ConstructorArguments[0];\r\n        var receivingMethod = new ReceivingMethod{ Static = methodSymbol.IsStatic, MethodSymbol = methodSymbol, Order = (int)param.Value! };\r\n\r\n        // Either append or create a new receiving method with a new list.\r\n        if (_eventTypeToReceivingMethods.TryGetValue(eventType.Type, out var tuple))\r\n        {\r\n            tuple.Item2.Add(receivingMethod);\r\n        }\r\n        else\r\n        {\r\n            tuple.Item1 = eventType.RefKind;\r\n            tuple.Item2 = new List<ReceivingMethod>{receivingMethod};\r\n            _eventTypeToReceivingMethods.Add(eventType.Type, tuple);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Maps the <see cref=\"IMethodSymbol\"/> to its <see cref=\"ITypeSymbol\"/> for organisation. \r\n    /// </summary>\r\n    /// <param name=\"methodSymbol\"></param>\r\n    private static void MapMethodToContainingType(IMethodSymbol methodSymbol)\r\n    {\r\n        var eventType = methodSymbol.Parameters[0];\r\n        var receivingMethod = new EventHook{ EventType = eventType.Type, MethodSymbol = methodSymbol, };\r\n\r\n        // Either append or create a new receiving method with a new list.\r\n        if (_containingTypeToReceivingMethods.TryGetValue(methodSymbol.ContainingType, out var tuple))\r\n        {\r\n            tuple.Add(receivingMethod);\r\n        }\r\n        else\r\n        {\r\n            var list = new List<EventHook>{receivingMethod};\r\n            _containingTypeToReceivingMethods.Add(methodSymbol.ContainingType, list);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Prepares the <see cref=\"EventBus\"/> by convertings the <see cref=\"_eventTypeToReceivingMethods\"/> to the eventbus model. \r\n    /// </summary>\r\n    private static void PrepareEventBus()\r\n    {\r\n        // Translate mapping to the model\r\n        foreach (var kvp in _eventTypeToReceivingMethods)\r\n        {\r\n            var eventCallMethod = new Method\r\n            {\r\n                RefKind = kvp.Value.Item1,\r\n                EventType = kvp.Key,\r\n                EventReceivingMethods = kvp.Value.Item2\r\n            };\r\n            eventCallMethod.EventReceivingMethods = eventCallMethod.EventReceivingMethods.OrderBy(method => method.Order).ToList();\r\n            _eventBus.Methods.Add(eventCallMethod);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Prepares the <see cref=\"Hooks\"/> by convertings the <see cref=\"_containingTypeToReceivingMethods\"/> to the hooks model. \r\n    /// </summary>\r\n    private static void PrepareHooks()\r\n    {\r\n        // Translate mapping to the model\r\n        foreach (var kvp in _containingTypeToReceivingMethods)\r\n        {\r\n\r\n            // Skip static classes since they need no hooks\r\n            if (kvp.Key.IsStatic)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            var hook = new ClassHooks\r\n            {\r\n                PartialClass = kvp.Key,\r\n                EventHooks = kvp.Value\r\n            };\r\n            _hooks.Instances.Add(hook);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Generates queries and partial classes for the found marked methods.\r\n    /// </summary>\r\n    /// <param name=\"compilation\">The <see cref=\"Compilation\"/>.</param>\r\n    /// <param name=\"methods\">The <see cref=\"ImmutableArray{MethodDeclarationSyntax}\"/> array, the methods which we will generate queries and classes for.</param>\r\n    /// <param name=\"context\">The <see cref=\"SourceProductionContext\"/>.</param>\r\n    private static void Generate(Compilation compilation, ImmutableArray<MethodDeclarationSyntax> methods, SourceProductionContext context)\r\n    {\r\n        if (methods.IsDefaultOrEmpty) return;\r\n        \r\n        // Init \r\n        _eventBus.Namespace = \"Arch.Bus\";\r\n        _eventBus.Methods = new List<Method>(512);\r\n        _eventTypeToReceivingMethods = new Dictionary<ITypeSymbol, (RefKind, IList<ReceivingMethod>)>(512, SymbolEqualityComparer.Default);\r\n        \r\n        _hooks.Instances = new List<ClassHooks>(512);\r\n        _containingTypeToReceivingMethods = new Dictionary<ITypeSymbol, IList<EventHook>>(512, SymbolEqualityComparer.Default);\r\n        \r\n        // Generate Query methods and map them to their classes\r\n        foreach (var methodSyntax in methods)\r\n        {\r\n            var semanticModel = compilation.GetSemanticModel(methodSyntax.SyntaxTree);\r\n            var methodSymbol = ModelExtensions.GetDeclaredSymbol(semanticModel, methodSyntax) as IMethodSymbol;\r\n\r\n            MapMethodToEventType(methodSymbol!);\r\n            MapMethodToContainingType(methodSymbol!);\r\n        }\r\n        \r\n        PrepareEventBus();\r\n        PrepareHooks();\r\n        \r\n        var template = new StringBuilder().AppendEventBus(ref _eventBus);\r\n        var hooks = new StringBuilder().AppendHooks(ref _hooks);\r\n        \r\n        context.AddSource($\"EventBus.g.cs\", CSharpSyntaxTree.ParseText(template.ToString()).GetRoot().NormalizeWhitespace().ToFullString());\r\n        context.AddSource($\"Hooks.g.cs\", CSharpSyntaxTree.ParseText(hooks.ToString()).GetRoot().NormalizeWhitespace().ToFullString());\r\n    }\r\n\r\n    /// <summary>\r\n    /// Compares <see cref=\"MethodDeclarationSyntax\"/>s to remove duplicates. \r\n    /// </summary>\r\n    class Comparer : IEqualityComparer<MethodDeclarationSyntax>\r\n    {\r\n        public static readonly Comparer Instance = new Comparer();\r\n\r\n        public bool Equals(MethodDeclarationSyntax x, MethodDeclarationSyntax y)\r\n        {\r\n            return x.Equals(y);\r\n        }\r\n\r\n        public int GetHashCode(MethodDeclarationSyntax obj)\r\n        {\r\n            return obj.GetHashCode();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.Extended.Sample/Arch.Extended.Sample.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <OutputType>Exe</OutputType>\r\n        <TargetFramework>net8.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <RootNamespace>Arch.Extended</RootNamespace>\r\n        <LangVersion>12</LangVersion>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n      <ProjectReference Include=\"..\\Arch.AOT.SourceGenerator\\Arch.AOT.SourceGenerator.csproj\" OutputItemType=\"Analyzer\" ReferenceOutputAssembly=\"false\"/>\r\n      <ProjectReference Include=\"..\\Arch.EventBus\\Arch.EventBus.csproj\" OutputItemType=\"Analyzer\" ReferenceOutputAssembly=\"false\" />\r\n      <ProjectReference Include=\"..\\Arch.LowLevel\\Arch.LowLevel.csproj\" />\r\n      <ProjectReference Include=\"..\\Arch.Persistence\\Arch.Persistence.csproj\" />\r\n      <ProjectReference Include=\"..\\Arch.Relationships\\Arch.Relationships.csproj\" />\r\n      <ProjectReference Include=\"..\\Arch.System.SourceGenerator\\Arch.System.SourceGenerator.csproj\" OutputItemType=\"Analyzer\" ReferenceOutputAssembly=\"false\" />\r\n      <ProjectReference Include=\"..\\Arch.System\\Arch.System.csproj\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n      <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n      <PackageReference Include=\"MonoGame.Framework.DesktopGL\" Version=\"3.8.1.303\" />\r\n      <PackageReference Include=\"NUnit\" Version=\"3.13.3\" />\r\n      <PackageReference Include=\"Utf8Json\" Version=\"1.3.7\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.Extended.Sample/Components.cs",
    "content": "﻿using System.Runtime.Serialization;\r\nusing Arch.AOT.SourceGenerator;\r\nusing Arch.Core;\r\nusing MessagePack;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\n\r\nnamespace Arch.Extended;\r\n\r\n/// <summary>\r\n///     The position of an entity.\r\n/// </summary>\r\npublic struct Position\r\n{\r\n\r\n    /// <summary>\r\n    ///     Its position.\r\n    /// </summary>\r\n    public Vector2 Vector2;\r\n    \r\n    /// <summary>\r\n    ///     Constructs a new <see cref=\"Position\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"x\">The x position.</param>\r\n    /// <param name=\"y\">The y position.</param>\r\n    public Position(float x, float y)\r\n    {\r\n        Vector2 = new Vector2(x, y);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Constructs a new <see cref=\"Position\"/> instance.\r\n    /// <remarks>Mostly required for <see cref=\"MessagePack\"/>.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"vector2\">The <see cref=\"Vector2\"/>, the position.</param>\r\n    public Position(Vector2 vector2)\r\n    {\r\n        Vector2 = vector2;\r\n    }\r\n};\r\n\r\n/// <summary>\r\n///     The velocity of an entity.\r\n/// </summary>\r\npublic struct Velocity\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Its velocity.\r\n    /// </summary>\r\n    public Vector2 Vector2;\r\n    \r\n    /// <summary>\r\n    ///     Constructs a new <see cref=\"Velocity\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"x\">The x velocity.</param>\r\n    /// <param name=\"y\">The y velocity.</param>\r\n    public Velocity(float x, float y)\r\n    {\r\n        Vector2 = new Vector2(x, y);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Constructs a new <see cref=\"Velocity\"/> instance.\r\n    /// <remarks>Mostly required for <see cref=\"MessagePack\"/>.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"vector2\">The <see cref=\"Vector2\"/>, the velocity.</param>\r\n    public Velocity(Vector2 vector2)\r\n    {\r\n        Vector2 = vector2;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n/// The sprite/texture of an entity. \r\n/// </summary>\r\npublic struct Sprite\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"Texture2D\"/> used.\r\n    /// </summary>\r\n    [IgnoreDataMember]\r\n    public Texture2D Texture2D;\r\n\r\n    /// <summary>\r\n    ///     The id of the texture, for serialisation. \r\n    /// </summary>\r\n    public byte TextureId;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"Color\"/> used. \r\n    /// </summary>\r\n    public Color Color;\r\n\r\n    /// <summary>\r\n    ///     Constructs a new <see cref=\"Sprite\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"texture2D\">Its <see cref=\"Texture2D\"/>.</param>\r\n    /// <param name=\"color\">Its <see cref=\"Color\"/>.</param>\r\n    public Sprite(Texture2D texture2D, Color color)\r\n    {\r\n        Texture2D = texture2D;\r\n        Color = color;\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.Extended.Sample/Extensions.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\n\r\nnamespace Arch.Extended;\r\n\r\npublic static class TextureExtensions\r\n{\r\n    /// <summary>\r\n    ///     Creates a square texture and returns it.\r\n    /// </summary>\r\n    /// <param name=\"graphicsDevice\"></param>\r\n    /// <param name=\"size\"></param>\r\n    /// <returns></returns>\r\n    public static Texture2D CreateSquareTexture(GraphicsDevice graphicsDevice, int size)\r\n    {\r\n        var texture = new Texture2D(graphicsDevice, size, size);\r\n        var data = new Color[size*size];\r\n        for(var i=0; i < data.Length; ++i) data[i] = Color.White;\r\n        texture.SetData(data);\r\n\r\n        return texture;\r\n    }\r\n}\r\n\r\npublic static class RandomExtensions\r\n{\r\n    /// <summary>\r\n    ///     Creates a random <see cref=\"Vector2\"/> inside the <see cref=\"Rectangle\"/> and returns it.\r\n    /// </summary>\r\n    /// <param name=\"random\">The <see cref=\"Random\"/> instance.</param>\r\n    /// <param name=\"rectangle\">A <see cref=\"Rectangle\"/> in which a <see cref=\"Vector2\"/> is generated. </param>\r\n    /// <returns>The generated <see cref=\"Vector2\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static Vector2 NextVector2(this Random random, in Rectangle rectangle)\r\n    {\r\n        return new Vector2(random.Next(rectangle.X, rectangle.X+rectangle.Width), random.Next(rectangle.Y, rectangle.Y+rectangle.Height));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a random <see cref=\"Vector2\"/> between two floats.\r\n    /// </summary>\r\n    /// <param name=\"random\">The <see cref=\"Random\"/> instance.</param>\r\n    /// <param name=\"min\">The minimum value.</param>\r\n    /// <param name=\"max\">The maximum value.</param>\r\n    /// <returns>A <see cref=\"Vector2\"/> between those to floats.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static Vector2 NextVector2(this Random random, float min, float max)\r\n    {\r\n        return new Vector2((float)(random.NextDouble() * (max - min) + min), (float)(random.NextDouble() * (max - min) + min));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a random <see cref=\"Color\"/>.\r\n    /// </summary>\r\n    /// <param name=\"random\">The <see cref=\"Random\"/> instance.</param>\r\n    /// <returns>A <see cref=\"Color\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static Color NextColor(this Random random)\r\n    {\r\n        return new Color(random.Next(0,255),random.Next(0,255),random.Next(0,255));\r\n    }\r\n}"
  },
  {
    "path": "Arch.Extended.Sample/Game.cs",
    "content": "﻿using System.IO.Compression;\r\nusing System.Runtime.Serialization;\r\nusing System.Text;\r\nusing System.Text.Json.Serialization;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Bus;\r\nusing Arch.Core.Extensions.Dangerous;\r\nusing Arch.Core.Utils;\r\nusing Arch.Persistence;\r\nusing Arch.Relationships;\r\nusing MessagePack;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing NUnit.Framework;\r\nusing Schedulers;\r\nusing Utf8Json;\r\nusing Utf8Json.Formatters;\r\nusing Utf8Json.Resolvers;\r\n\r\nnamespace Arch.Extended;\r\n\r\n/// <summary>\r\n///     The <see cref=\"Game\"/> which represents the game and implements all the important monogame features.\r\n/// </summary>\r\npublic class Game : Microsoft.Xna.Framework.Game\r\n{\r\n    // The world and a job scheduler for multithreading\r\n    private World _world = null!;\r\n    private JobScheduler _jobScheduler = null!;\r\n    \r\n    // Our systems processing entities\r\n    private System.Group<GameTime> _systems = null!;\r\n    private DrawSystem _drawSystem = null!;\r\n\r\n    // Monogame stuff\r\n    private GraphicsDeviceManager _graphics;\r\n    private SpriteBatch _spriteBatch = null!;\r\n    private Texture2D _texture2D = null!;\r\n    private Random _random = null!;\r\n    \r\n    public Game()\r\n    {\r\n        _graphics = new GraphicsDeviceManager(this);\r\n        Content.RootDirectory = \"Content\";\r\n    }\r\n    \r\n    protected override void Initialize()\r\n    {\r\n        // Setup texture and randomness\r\n        _random = new Random();\r\n        _texture2D = TextureExtensions.CreateSquareTexture(GraphicsDevice, 10);\r\n\r\n        base.Initialize();\r\n    }\r\n    \r\n    protected override void LoadContent()\r\n    {\r\n        // Create a new SpriteBatch, which can be used to draw textures.\r\n        _spriteBatch = new SpriteBatch(GraphicsDevice);\r\n    }\r\n    \r\n    protected override void BeginRun()\r\n    {\r\n        base.BeginRun();\r\n        \r\n        // Create world & JobScheduler for multithreading\r\n        _world = World.Create();\r\n        _jobScheduler = new(\r\n            new JobScheduler.Config\r\n            {\r\n                ThreadPrefixName = \"Arch.Samples\",\r\n                ThreadCount = 0,\r\n                MaxExpectedConcurrentJobs = 64,\r\n                StrictAllocationMode = false,\r\n            }\r\n        );\r\n        World.SharedJobScheduler = _jobScheduler;\r\n        \r\n        // Spawn in entities with position, velocity and sprite\r\n        for (var index = 0; index < 10; index++)\r\n        {\r\n            _world.Create(\r\n                new Position{ Vector2 = _random.NextVector2(GraphicsDevice.Viewport.Bounds) }, \r\n                new Velocity{ Vector2 = _random.NextVector2(-0.25f,0.25f) }, \r\n                new Sprite{ Texture2D = _texture2D, Color = _random.NextColor() }\r\n            );\r\n        }\r\n        \r\n        //Serializer is not updated yet. \r\n        // Serialize world and deserialize it back. Just for showcasing the serialization, its actually not necessary.\r\n        // var archSerializer = new ArchJsonSerializer(new SpriteSerializer{GraphicsDevice = GraphicsDevice});\r\n        // var worldJson = archSerializer.ToJson(_world);\r\n        // _world = archSerializer.FromJson(worldJson);\r\n        \r\n        var archSerializer = new ArchBinarySerializer(new SpriteSerializer{GraphicsDevice = GraphicsDevice});\r\n        var worldJson = archSerializer.Serialize(_world);\r\n        _world = archSerializer.Deserialize(worldJson);\r\n        \r\n        // Create systems, running in order\r\n        _systems = new System.Group<GameTime>(\r\n            \"Systems\",\r\n            new MovementSystem(_world, GraphicsDevice.Viewport.Bounds),\r\n            new ColorSystem(_world),\r\n            new DebugSystem(_world)\r\n        );\r\n        _drawSystem = new DrawSystem(_world, _spriteBatch);  // Draw system must be its own system since monogame differentiates between update and draw. \r\n        \r\n        // Initialize systems\r\n        _systems.Initialize();\r\n        _drawSystem.Initialize();\r\n    }\r\n\r\n    protected override void Update(GameTime gameTime)\r\n    {\r\n        // Exit game on press\r\n        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit();\r\n        \r\n        // Forward keyboard state as an event to another handles by using the eventbus\r\n        var @event = (_world, Keyboard.GetState());\r\n        EventBus.Send(ref @event);\r\n        \r\n         // Continue entity movement by adding velocity to all\r\n        if (Keyboard.GetState().IsKeyDown(Keys.I))\r\n        {\r\n            // Query for velocity entities and remove their velocity to make them stop moving.\r\n            var queryDesc = new QueryDescription().WithNone<Velocity>();\r\n            _world.Add(in queryDesc, new Velocity { Vector2 = _random.NextVector2(-0.25f, 0.25f) });\r\n        }\r\n\r\n        // Pause entity movement by removing velocity from all\r\n        if (Keyboard.GetState().IsKeyDown(Keys.O))\r\n        {\r\n            // Query for velocity entities and remove their velocity to make them stop moving.\r\n            var queryDesc = new QueryDescription().WithAll<Velocity>();\r\n            _world.Remove<Velocity>(in queryDesc);\r\n        }\r\n\r\n        // Add a random amount of new entities\r\n        if (Keyboard.GetState().IsKeyDown(Keys.K))\r\n        {\r\n            // Bulk create entities\r\n            var amount = Random.Shared.Next(0, 500);\r\n            Span<Entity> entities = stackalloc Entity[amount];\r\n            _world.Create(entities,[typeof(Position), typeof(Velocity), typeof(Sprite)], amount);\r\n\r\n            // Set variables\r\n            foreach (var entity in entities)\r\n            { \r\n\r\n#if DEBUG_PUREECS || RELEASE_PUREECS\r\n                _world.Set(entity,\r\n                    new Position { Vector2 = _random.NextVector2(GraphicsDevice.Viewport.Bounds) },\r\n                    new Velocity { Vector2 = _random.NextVector2(-0.25f, 0.25f) },\r\n                    new Sprite { Texture2D = _texture2D, Color = _random.NextColor() }\r\n                );\r\n#else\r\n                entity.Set(\r\n                    new Position { Vector2 = _random.NextVector2(GraphicsDevice.Viewport.Bounds) },\r\n                    new Velocity { Vector2 = _random.NextVector2(-0.25f, 0.25f) },\r\n                    new Sprite { Texture2D = _texture2D, Color = _random.NextColor() }\r\n                );\r\n#endif\r\n            }\r\n        }\r\n\r\n        // Remove a random amount of new entities\r\n        if (Keyboard.GetState().IsKeyDown(Keys.L))\r\n        {\r\n            // Find all entities\r\n            var entities = new Entity[_world.Size];\r\n            _world.GetEntities(new QueryDescription(), entities.AsSpan());\r\n\r\n            // Delete random entities\r\n            var amount = Random.Shared.Next(0, Math.Min(500, entities.Length));\r\n            for (var index = 0; index < amount; index++)\r\n            {\r\n                var randomIndex = _random.Next(0, entities.Length);\r\n                var randomEntity = entities[randomIndex];\r\n\r\n#if DEBUG_PUREECS || RELEASE_PUREECS\r\n                if (_world.IsAlive(randomEntity))\r\n#else\r\n                if (randomEntity.IsAlive())\r\n#endif\r\n                {\r\n                    _world.Destroy(randomEntity);\r\n                }\r\n\r\n                entities[randomIndex] = Entity.Null;\r\n            }\r\n        }\r\n        \r\n        // Update systems\r\n        _systems.BeforeUpdate(in gameTime);\r\n        _systems.Update(in gameTime);\r\n        _systems.AfterUpdate(in gameTime);\r\n        base.Update(gameTime);\r\n    }\r\n    \r\n    protected override void Draw(GameTime gameTime)\r\n    {\r\n        _graphics.GraphicsDevice.Clear(Color.CornflowerBlue);\r\n        \r\n        // Update draw system and draw stuff\r\n        _drawSystem.BeforeUpdate(in gameTime);\r\n        _drawSystem.Update(in gameTime);\r\n        _drawSystem.AfterUpdate(in gameTime);\r\n        base.Draw(gameTime);\r\n    }\r\n\r\n    protected override void EndRun()\r\n    {\r\n        base.EndRun();\r\n        \r\n        // Destroy world and shutdown the jobscheduler \r\n        World.Destroy(_world);\r\n        _jobScheduler.Dispose();\r\n        \r\n        // Dispose systems\r\n        _systems.Dispose();\r\n    }\r\n}"
  },
  {
    "path": "Arch.Extended.Sample/Program.cs",
    "content": "﻿// See https://aka.ms/new-console-template for more information\r\n\r\nusing Microsoft.Xna.Framework;\r\nusing Game = Arch.Extended.Game;\r\n\r\n\r\n// Info : \r\n// This sample demonstrates a example usage of arch. \r\n// Especially a few different iteration techniques for entity iterations. \r\n// Its not a full demonstration of all features. \r\n// Hit \"delete\" to remove velocity from all entities\r\n\r\n// Disclaimer : \r\n// You can spawn in to 1 million entities, then the performance starts dropping.\r\n// The bottleneck is not the ECS framework, its actually the rendering ( Monogame Spritebatch ).\r\n\r\nConsole.WriteLine(\"Sample App starts...\");\r\nusing var game = new Game();\r\ngame.Run();\r\n\r\nEnvironment.Exit(0);"
  },
  {
    "path": "Arch.Extended.Sample/Serializer.cs",
    "content": "﻿using MessagePack;\r\nusing MessagePack.Formatters;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Utf8Json;\r\n\r\nnamespace Arch.Extended;\r\n\r\n/// <summary>\r\n///     The <see cref=\"SpriteSerializer\"/> class\r\n///     is a <see cref=\"IJsonFormatter{T}\"/> for (de)serialising a <see cref=\"Sprite\"/>.\r\n/// </summary>\r\npublic class SpriteSerializer : IJsonFormatter<Sprite>, IMessagePackFormatter<Sprite>\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"GraphicsDevice\"/> to create <see cref=\"Texture2D\"/>s from. \r\n    /// </summary>\r\n    public GraphicsDevice GraphicsDevice { get; set; } = null!;\r\n\r\n    public void Serialize(ref JsonWriter writer, Sprite value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteBeginObject();\r\n        \r\n        // Write color\r\n        writer.WritePropertyName(\"color\");\r\n        writer.WriteUInt32(value.Color.PackedValue);\r\n        writer.WriteValueSeparator();\r\n        \r\n        // Write texture id\r\n        writer.WritePropertyName(\"textureId\");\r\n        writer.WriteUInt16(value.TextureId);\r\n\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    public Sprite Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n        \r\n        // Read color\r\n        reader.ReadPropertyName();\r\n        var packedColor = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        // Read textureid\r\n        reader.ReadPropertyName();\r\n        var textureId = reader.ReadUInt16();\r\n\r\n        // Create color and texture\r\n        var color = new Color { PackedValue = packedColor };\r\n        var texture = textureId switch\r\n        {\r\n            1 => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10),\r\n            _ => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10)\r\n        };\r\n\r\n        reader.ReadIsEndObject();\r\n        return new Sprite(texture, color);\r\n    }\r\n\r\n    public void Serialize(ref MessagePackWriter writer, Sprite value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write color\r\n        writer.WriteUInt32(value.Color.PackedValue);\r\n\r\n        // Write texture id\r\n        writer.WriteUInt16(value.TextureId);\r\n    }\r\n\r\n    public Sprite Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Read color\r\n        var packedColor = reader.ReadUInt32();\r\n   \r\n        // Read textureid\r\n        var textureId = reader.ReadUInt16();\r\n\r\n        // Create color and texture\r\n        var color = new Color { PackedValue = packedColor };\r\n        var texture = textureId switch\r\n        {\r\n            1 => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10),\r\n            _ => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10)\r\n        };\r\n        \r\n        return new Sprite(texture, color);\r\n    }\r\n}"
  },
  {
    "path": "Arch.Extended.Sample/Systems.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing Arch.Bus;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.LowLevel;\r\nusing Arch.System;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace Arch.Extended;\r\n\r\n/// <summary>\r\n///     The movement system makes the entities move and bounce properly. \r\n/// </summary>\r\npublic partial class MovementSystem : BaseSystem<World, GameTime>\r\n{\r\n    \r\n    /// <summary>\r\n    ///     A rectangle which specifies the viewport.\r\n    ///     Needed so that the entities do not wander outside the viewport.\r\n    /// </summary>\r\n    private readonly Rectangle _viewport;\r\n    \r\n    /// <summary>\r\n    ///     Creates a <see cref=\"MovementSystem\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> used.</param>\r\n    /// <param name=\"viewport\">The games <see cref=\"Viewport\"/>.</param>\r\n    public MovementSystem(World world, Rectangle viewport) : base(world) { _viewport = viewport;}\r\n\r\n    /// <summary>\r\n    ///     Called for each <see cref=\"Entity\"/> to move it.\r\n    ///     The calling takes place through the source generated method \"MoveQuery\" on <see cref=\"BaseSystem{W,T}.Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"time\">The <see cref=\"GameTime\"/>, passed by the \"MoveQuery\".</param>\r\n    /// <param name=\"pos\">The <see cref=\"Position\"/> of the <see cref=\"Entity\"/>. Passed by the \"MoveQuery\".</param>\r\n    /// <param name=\"vel\">The <see cref=\"Velocity\"/> of the <see cref=\"Entity\"/>. Passed by the \"MoveQuery\".</param>\r\n    [Query(Parallel = true)]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void Move([Data] GameTime time, ref Position pos, ref Velocity vel)\r\n    {\r\n        pos.Vector2 += time.ElapsedGameTime.Milliseconds * vel.Vector2;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Called for each <see cref=\"Entity\"/> to move it.\r\n    ///     The calling takes place through the source generated method \"MoveQuery\" on <see cref=\"BaseSystem{W,T}.Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"pos\">The <see cref=\"Position\"/> of the <see cref=\"Entity\"/>. Passed by the \"MoveQuery\".</param>\r\n    /// <param name=\"vel\">The <see cref=\"Velocity\"/> of the <see cref=\"Entity\"/>. Passed by the \"MoveQuery\".</param>\r\n    [Query]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Bounce(ref Position pos, ref Velocity vel)\r\n    {\r\n        if (pos.Vector2.X >= _viewport.X + _viewport.Width)\r\n            vel.Vector2.X = -vel.Vector2.X;\r\n            \r\n        if (pos.Vector2.Y >= _viewport.Y + _viewport.Height)\r\n            vel.Vector2.Y = -vel.Vector2.Y;\r\n            \r\n        if (pos.Vector2.X <= _viewport.X)\r\n            vel.Vector2.X = -vel.Vector2.X;\r\n            \r\n        if (pos.Vector2.Y <= _viewport.Y)\r\n            vel.Vector2.Y = -vel.Vector2.Y;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     Color system, modifies each entities color slowly. \r\n/// </summary>\r\npublic partial class ColorSystem : BaseSystem<World, GameTime>\r\n{\r\n    /// <summary>\r\n    ///     Creates an <see cref=\"ColorSystem\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"world\"></param>\r\n    public ColorSystem(World world) : base(world) {}\r\n\r\n    /// <summary>\r\n    ///     Called for each <see cref=\"Entity\"/> to change its color.\r\n    ///     The calling takes place through the source generated method \"ChangeColorQuery\" on <see cref=\"BaseSystem{W,T}.Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"time\">The <see cref=\"GameTime\"/> Passed by the \"MoveQuery\".</param>\r\n    /// <param name=\"sprite\">The <see cref=\"Sprite\"/> of the <see cref=\"Entity\"/>. Passed by the \"ChangeColorQuery\".</param>\r\n    [Query]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void ChangeColor([Data] GameTime time, ref Sprite sprite)\r\n    {\r\n        sprite.Color.R += (byte)(time.ElapsedGameTime.TotalMilliseconds * 0.08);\r\n        sprite.Color.G += (byte)(time.ElapsedGameTime.TotalMilliseconds * 0.08);\r\n        sprite.Color.B += (byte)(time.ElapsedGameTime.TotalMilliseconds * 0.08);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The draw system, handles the drawing of <see cref=\"Entity\"/> sprites at their position. \r\n/// </summary>\r\npublic partial class DrawSystem : BaseSystem<World, GameTime>\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"SpriteBatch\"/> used for drawing all <see cref=\"Entity\"/>s.\r\n    /// </summary>\r\n    private readonly SpriteBatch _batch;\r\n    \r\n    /// <summary>\r\n    ///     Creates a <see cref=\"DrawSystem\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> used.</param>\r\n    /// <param name=\"batch\">The <see cref=\"SpriteBatch\"/> used.</param>\r\n    public DrawSystem(World world, SpriteBatch batch) : base(world) { _batch = batch;}\r\n\r\n    /// <summary>\r\n    ///     Is called before the <see cref=\"BaseSystem{W,T}.Update\"/> to start with the <see cref=\"SpriteBatch\"/> recording.\r\n    /// </summary>\r\n    /// <param name=\"t\">The <see cref=\"GameTime\"/>.</param>\r\n    public override void BeforeUpdate(in GameTime t)\r\n    {\r\n        base.BeforeUpdate(in t);\r\n        _batch.Begin();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Called for each <see cref=\"Entity\"/> to draw it.\r\n    ///     The calling takes place through the source generated method \"DrawQuery\" on <see cref=\"BaseSystem{W,T}.Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"position\">The <see cref=\"Position\"/> of the <see cref=\"Entity\"/>. Passed by the \"DrawQuery\".</param>\r\n    /// <param name=\"sprite\">The <see cref=\"Sprite\"/> of the <see cref=\"Entity\"/>. Passed by the \"DrawQuery\".</param>\r\n    [Query]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Draw(ref Position position, ref Sprite sprite)\r\n    {\r\n        _batch.Draw(sprite.Texture2D, position.Vector2, sprite.Color);  // Draw\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Is called after the <see cref=\"BaseSystem{W,T}.Update\"/> to stop the <see cref=\"SpriteBatch\"/> recording.\r\n    /// </summary>\r\n    /// <param name=\"t\">The <see cref=\"GameTime\"/>.</param>\r\n    public override void AfterUpdate(in GameTime t)\r\n    {\r\n        base.AfterUpdate(in t);\r\n        _batch.End();\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The debug system, shows how you can combine source generated queries and default ones. \r\n/// </summary>\r\npublic partial class DebugSystem : BaseSystem<World, GameTime>\r\n{\r\n    /// <summary>\r\n    ///     A custom <see cref=\"QueryDescription\"/> which targets <see cref=\"Entity\"/>s with <see cref=\"Position\"/> and <see cref=\"Sprite\"/> without <see cref=\"Velocity\"/>.\r\n    /// </summary>\r\n    private readonly QueryDescription _customQuery = new QueryDescription().WithAll<Position, Sprite>().WithNone<Velocity>();\r\n\r\n    /// <summary>\r\n    ///     Creates a new <see cref=\"DebugSystem\"/> instance. \r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> used.</param>\r\n    public DebugSystem(World world) : base(world)\r\n    {\r\n        Hook();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Implements <see cref=\"BaseSystem{W,T}.Update\"/> to call the custom Query and the source generated one. \r\n    /// </summary>\r\n    /// <param name=\"t\">The <see cref=\"GameTime\"/>.</param>\r\n    public override void Update(in GameTime t)\r\n    {\r\n        World.Query(in _customQuery, entity => Console.WriteLine($\"Custom : {entity}\"));  // Manual query\r\n        PrintEntitiesWithoutVelocityQuery(World);  // Call source generated query, which calls the PrintEntitiesWithoutVelocity method\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Called for each <see cref=\"Entity\"/> with <see cref=\"Position\"/> and <see cref=\"Sprite\"/> without <see cref=\"Velocity\"/> to print it.\r\n    ///     The calling takes place through the source generated method \"PrintEntitiesWithoutVelocityQuery\" on <see cref=\"DebugSystem.Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"en\">The <see cref=\"Entity\"/>. Passed by the \"PrintEntitiesWithoutVelocityQuery\", you can also pass components or data parameters as usual.</param>\r\n    [Query]\r\n    [All<Position, Sprite>, None<Velocity>]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void PrintEntitiesWithoutVelocity(in Entity en)\r\n    {\r\n        Console.WriteLine(en);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Receives dispatched keyboard events and if the a key was pressed, prints it.\r\n    ///     Runs before any other event receiver of this kind.\r\n    /// </summary>\r\n    /// <param name=\"tuple\">The event listened to.</param>\r\n    [Event(order: 0)]\r\n    public void OnKeyboardEventPrint(ref (World world, KeyboardState state) tuple)\r\n    {\r\n        if (!tuple.state.IsKeyDown(Keys.A)) return;\r\n        Console.WriteLine($\"Key a was pressed.\");\r\n    }\r\n}\r\n\r\n/// <summary>\r\n/// A event handler class using the source generated eventbus to intercept and react to events to decouple logic. \r\n/// </summary>\r\npublic static partial class EventHandler\r\n{\r\n\r\n    /// <summary>\r\n    /// Listens for <see cref=\"ValueTuple{T1,T2}\"/> events with a <see cref=\"World\"/> and <see cref=\"KeyboardState\"/> to check if the delte key was pressed.\r\n    /// If thats the case, it will remove the <see cref=\"Velocity\"/> component from all of them. \r\n    /// </summary>\r\n    /// <param name=\"tuple\"></param>\r\n    [Event(order: 1)]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void OnDeleteStopEntities(ref (World world, KeyboardState state) tuple)\r\n    {\r\n        if (!tuple.state.IsKeyDown(Keys.Delete)) return;\r\n        \r\n        // Query for velocity entities and remove their velocity to make them stop moving. \r\n        var queryDesc = new QueryDescription().WithAll<Velocity>();\r\n        tuple.world.Query(in queryDesc, entity => entity.Remove<Velocity>());\r\n    }\r\n}"
  },
  {
    "path": "Arch.Extended.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 17\r\nVisualStudioVersion = 17.8.34408.163\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.System.SourceGenerator\", \"Arch.System.SourceGenerator\\Arch.System.SourceGenerator.csproj\", \"{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.Extended.Sample\", \"Arch.Extended.Sample\\Arch.Extended.Sample.csproj\", \"{ED61027D-1586-4349-A6F8-17665C786678}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.System\", \"Arch.System\\Arch.System.csproj\", \"{39363918-BFC7-43BF-8307-F5581225FB41}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.EventBus\", \"Arch.EventBus\\Arch.EventBus.csproj\", \"{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.LowLevel\", \"Arch.LowLevel\\Arch.LowLevel.csproj\", \"{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.LowLevel.Tests\", \"Arch.LowLevel.Tests\\Arch.LowLevel.Tests.csproj\", \"{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.Persistence\", \"Arch.Persistence\\Arch.Persistence.csproj\", \"{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.Relationships\", \"Arch.Relationships\\Arch.Relationships.csproj\", \"{533453B9-957E-401E-B639-DC81DD0265EC}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.Relationships.Tests\", \"Arch.Relationships.Tests\\Arch.Relationships.Tests.csproj\", \"{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.System.SourceGenerator.SnapshotTests\", \"Arch.System.SourceGenerator.SnapshotTests\\Arch.System.SourceGenerator.SnapshotTests.csproj\", \"{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Arch.System.SourceGenerator.Tests\", \"Arch.System.SourceGenerator.Tests\\Arch.System.SourceGenerator.Tests.csproj\", \"{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Arch.AOT.SourceGenerator\", \"Arch.AOT.SourceGenerator\\Arch.AOT.SourceGenerator.csproj\", \"{454AC3E0-A46A-4620-A377-3A360B8D11A3}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Arch.Persistence.Tests\", \"Arch.Persistence.Tests\\Arch.Persistence.Tests.csproj\", \"{15E851C2-ACD6-4626-A7E4-46AA4CCD3BD5}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{ED61027D-1586-4349-A6F8-17665C786678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{ED61027D-1586-4349-A6F8-17665C786678}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{ED61027D-1586-4349-A6F8-17665C786678}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{ED61027D-1586-4349-A6F8-17665C786678}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{39363918-BFC7-43BF-8307-F5581225FB41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{39363918-BFC7-43BF-8307-F5581225FB41}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{39363918-BFC7-43BF-8307-F5581225FB41}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{39363918-BFC7-43BF-8307-F5581225FB41}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{533453B9-957E-401E-B639-DC81DD0265EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{533453B9-957E-401E-B639-DC81DD0265EC}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{533453B9-957E-401E-B639-DC81DD0265EC}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{533453B9-957E-401E-B639-DC81DD0265EC}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{454AC3E0-A46A-4620-A377-3A360B8D11A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{454AC3E0-A46A-4620-A377-3A360B8D11A3}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{454AC3E0-A46A-4620-A377-3A360B8D11A3}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{454AC3E0-A46A-4620-A377-3A360B8D11A3}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{15E851C2-ACD6-4626-A7E4-46AA4CCD3BD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{15E851C2-ACD6-4626-A7E4-46AA4CCD3BD5}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{15E851C2-ACD6-4626-A7E4-46AA4CCD3BD5}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{15E851C2-ACD6-4626-A7E4-46AA4CCD3BD5}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "Arch.Extended.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\r\n\t<s:String x:Key=\"/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue\">/usr/local/share/dotnet/sdk/8.0.101/MSBuild.dll</s:String>\r\n\t<s:Int64 x:Key=\"/Default/Environment/Hierarchy/Build/BuildTool/MsbuildVersion/@EntryValue\">4294967293</s:Int64></wpf:ResourceDictionary>"
  },
  {
    "path": "Arch.LowLevel/Arch.LowLevel.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFrameworks>net7.0; net6.0; netstandard2.1</TargetFrameworks>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <PackageId>Arch.LowLevel</PackageId>\r\n        <Title>Arch.LowLevel</Title>\r\n        <Version>1.1.5</Version>\r\n        <Authors>genaray</Authors>\r\n        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\r\n        <Description>LowLevel tools for arch.</Description>\r\n        <PackageReleaseNotes>Refactored JaggedArrays.\r\nIncreased performance of JaggedArrays.\r\nAdded Array, a new class that acts as a Wrapper around normal generic Arrays for unsafe operations. \r\nAdded tests. \r\nBug fixes.</PackageReleaseNotes>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <IsPackable>true</IsPackable>\r\n\r\n        <LangVersion>11</LangVersion>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageLicenseUrl></PackageLicenseUrl>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n\r\n        <UnityPublish>true</UnityPublish>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n      <PackageReference Include=\"CommunityToolkit.HighPerformance\" Version=\"8.2.2\" />\r\n      <PackageReference Include=\"System.Runtime.CompilerServices.Unsafe\" Version=\"6.0.0\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.LowLevel/Array.cs",
    "content": "﻿using System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing System.Text;\r\nusing CommunityToolkit.HighPerformance;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"Array{T}\"/> struct\r\n///     represents an allocated array of managed items which wraps them to acess the items via an unsafe operations.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The managed generic.</typeparam>\r\n[DebuggerTypeProxy(typeof(ArrayDebugView<>))]\r\npublic readonly struct Array<T> \r\n{\r\n    \r\n    /// <summary>\r\n    ///     The static empty <see cref=\"Array{T}\"/>.\r\n    /// </summary>\r\n    internal static Array<T> Empty = new(0);\r\n    \r\n    /// <summary>\r\n    ///     The pointer, pointing towards the first element of this <see cref=\"Array{T}\"/>.\r\n    /// </summary>\r\n    internal readonly T[] _array;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Array{T}\"/>.\r\n    ///     Allocates the array for the passed count of items.\r\n    /// </summary>\r\n    /// <param name=\"count\">The arrays count or capacity.</param>\r\n    public Array(int count)\r\n    {\r\n        _array = new T[count];\r\n        Count = count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Array{T}\"/>.\r\n    ///     Allocates the array for the passed count of items.\r\n    /// </summary>\r\n    /// <param name=\"array\">The array used.</param>\r\n    public Array(T[] array)\r\n    {\r\n        this._array = array;\r\n        Count = array.Length;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The count of this <see cref=\"Array{T}\"/> instance, its capacity.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The count of this <see cref=\"UnsafeArray{T}\"/> instance, its capacity.\r\n    /// </summary>\r\n    public int Length\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns a reference to an item at a given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref _array.DangerousGetReferenceAt(i);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeArray{T}\"/> instance into a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>A new instance of <see cref=\"Span{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Span<T> AsSpan()\r\n    {\r\n        return MemoryMarshal.CreateSpan(ref this[0], Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"UnsafeEnumerator{T}\"/> for ref acessing the array content.\r\n    /// </summary>\r\n    /// <returns>A new <see cref=\"UnsafeEnumerator{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Enumerator<T> GetEnumerator()\r\n    {\r\n        return new Enumerator<T>(AsSpan());\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"other\">The other <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns>True if equal, oterwhise false.</returns>\r\n    public bool Equals(Array<T> other)\r\n    {\r\n        return _array == other._array && Count == other.Count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"obj\">The other <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns>True if equal, oterwhise false.</returns>\r\n    public override bool Equals(object? obj)\r\n    {\r\n        return obj is Array<T> other && Equals(other);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns></returns>\r\n    public static bool operator ==(Array<T> left, Array<T> right)\r\n    {\r\n        return left.Equals(right);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for inequality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns></returns>\r\n    public static bool operator !=(Array<T> left, Array<T> right)\r\n    {\r\n        return !left.Equals(right);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the hash of this <see cref=\"UnsafeArray\"/>.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public override int GetHashCode()\r\n    {\r\n        return _array.GetHashCode();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts an <see cref=\"Array{T}\"/> into a generic array.\r\n    /// </summary>\r\n    /// <param name=\"instance\">The <see cref=\"Array{T}\"/> instance.</param>\r\n    /// <returns>The array.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static implicit operator T[](Array<T> instance)\r\n    {\r\n        return instance._array;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts an <see cref=\"Array{T}\"/> into a generic array.\r\n    /// </summary>\r\n    /// <param name=\"instance\">The <see cref=\"Array{T}\"/> instance.</param>\r\n    /// <returns>The array.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static implicit operator Array<T>(T[] instance)\r\n    {\r\n        return new Array<T>(instance);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeArray{T}\"/> to a string.\r\n    /// </summary>\r\n    /// <returns>The string.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public override string ToString()\r\n    {\r\n        var items = new StringBuilder();\r\n        foreach (ref var item in this)\r\n        {\r\n            items.Append($\"{item},\");\r\n        }\r\n        items.Length--;\r\n        return $\"Array<{typeof(T).Name}>[{Count}]{{{items}}}\";\r\n    }\r\n}\r\n\r\n\r\n/// <summary>\r\n/// Array.\r\n/// </summary>\r\npublic unsafe struct Array\r\n{\r\n\r\n    /// <summary>\r\n    ///     Returns an empty <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The generic type.</typeparam>\r\n    /// <returns>The empty <see cref=\"UnsafeArray{T}\"/>.</returns>\r\n    public static Array<T> Empty<T>()\r\n    {\r\n        return Array<T>.Empty;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///  Copies the a part of the <see cref=\"UnsafeArray{T}\"/> to the another <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"source\">The source <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"index\">The start index in the source <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"destination\">The destination <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"destinationIndex\">The start index in the destination <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"length\">The length indicating the amount of items being copied.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void Copy<T>(ref Array<T> source, int index, ref Array<T> destination, int destinationIndex, int length)\r\n    {\r\n        System.Array.Copy(source._array, index, destination._array, destinationIndex, length);\r\n    }\r\n\r\n\r\n    /// <summary>\r\n    ///     Fills an <see cref=\"UnsafeArray{T}\"/> with a given value.\r\n    /// </summary>\r\n    /// <param name=\"source\">The <see cref=\"UnsafeArray{T}\"/> instance.</param>\r\n    /// <param name=\"value\">The value.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void Fill<T>(ref Array<T> source, in T value = default!) \r\n    {\r\n        source.AsSpan().Fill(value);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Resizes an <see cref=\"UnsafeArray{T}\"/> to a new <paramref name=\"newCapacity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"source\">The <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"newCapacity\">The new capacity.</param>\r\n    /// <typeparam name=\"T\">The generic type.</typeparam>\r\n    /// <returns>The new resized <see cref=\"UnsafeArray{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static Array<T> Resize<T>(ref Array<T> source, int newCapacity) \r\n    {\r\n        // Create a new array with the new capacity\r\n        var destination = new Array<T>(newCapacity);\r\n    \r\n        // Calculate the number of elements to copy\r\n        var lengthToCopy = Math.Min(source.Length, newCapacity);\r\n        Copy(ref source, 0, ref destination, 0, lengthToCopy);\r\n        return destination;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     A debug view for the <see cref=\"UnsafeArray{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged type.</typeparam>\r\ninternal class ArrayDebugView<T> where T : unmanaged\r\n{\r\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\r\n    private readonly Array<T> _entity;\r\n\r\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\r\n    public T[] Items\r\n    {\r\n        get\r\n        {\r\n            var items = new T[_entity.Count];\r\n            _entity.AsSpan().CopyTo(items);\r\n            return items;\r\n        }\r\n    }\r\n\r\n    public ArrayDebugView(Array<T> entity) => _entity = entity;\r\n}"
  },
  {
    "path": "Arch.LowLevel/Enumerators.cs",
    "content": "﻿using System.Collections;\r\nusing System.Runtime.CompilerServices;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The <see cref=\"Enumerator{T}\"/> is a basic implementation of an enumerator for the <see cref=\"Array{T}\"/>>.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic unsafe ref struct Enumerator<T> \r\n{\r\n    private readonly Span<T> _list;\r\n    private readonly int _count;\r\n    private int _index;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Enumerator{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"list\">The <see cref=\"Span{T}\"/>.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal Enumerator(Span<T> list)\r\n    {\r\n        _list = list;\r\n        _count = list.Length;\r\n        _index = -1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    public readonly ref T Current => ref _list[_index];\r\n\r\n    /// <summary>\r\n    ///     Moves to the next item.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public bool MoveNext()\r\n    {\r\n        return unchecked(++_index < _count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Resets the enumerator.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        _index = -1;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeIEnumerator{T}\"/> is a basic implementation of the <see cref=\"IEnumerator{T}\"/> interface for the <see cref=\"UnsafeList{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic unsafe struct UnsafeIEnumerator<T> : IEnumerator<T> where T : unmanaged\r\n{\r\n    private readonly T* _list;\r\n    private readonly int _count;\r\n    private int _index;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeIEnumerator{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"list\">The <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"count\">Count.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal UnsafeIEnumerator(T* list, int count)\r\n    {\r\n        _list = list;\r\n        _count = count;\r\n        _index = -1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    public T Current => _list[_index];\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    object IEnumerator.Current => _list[_index];\r\n\r\n    /// <summary>\r\n    ///     Disposes this enumerator.\r\n    /// </summary>\r\n    public void Dispose() { }   // nop\r\n\r\n    /// <summary>\r\n    ///     Moves to the next item.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public bool MoveNext()\r\n    {\r\n        return unchecked(++_index < _count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Resets the enumerator.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        _index = -1;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeIEnumerator{T}\"/> is a basic implementation of the <see cref=\"IEnumerator{T}\"/> interface for the <see cref=\"UnsafeList{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic unsafe ref struct UnsafeEnumerator<T> where T : unmanaged\r\n{\r\n    private readonly T* _list;\r\n    private readonly int _count;\r\n    private int _index;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeIEnumerator{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"list\">The <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"count\">Count.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal UnsafeEnumerator(T* list, int count)\r\n    {\r\n        _list = list;\r\n        _count = count;\r\n        _index = -1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    public ref T Current => ref _list[_index];\r\n\r\n    /// <summary>\r\n    ///     Moves to the next item.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public bool MoveNext()\r\n    {\r\n        return unchecked(++_index < _count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Resets the enumerator.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        _index = -1;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ReverseIEnumerator{T}\"/> is a basic implementation of the <see cref=\"IEnumerator{T}\"/> interface for iterating backwards.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic unsafe struct ReverseIEnumerator<T> : IEnumerator<T> where T : unmanaged\r\n{\r\n    private readonly T* _list;\r\n    private readonly int _count;\r\n    private int _index;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeIEnumerator{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"list\">The <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"count\">Count.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal ReverseIEnumerator(T* list, int count)\r\n    {\r\n        _list = list;\r\n        _count = count;\r\n        _index = count+1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    public T Current => _list[_index-1];\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    object IEnumerator.Current => _list[_index-1];\r\n\r\n    /// <summary>\r\n    ///     Disposes this enumerator.\r\n    /// </summary>\r\n    public void Dispose() { }   // nop\r\n\r\n    /// <summary>\r\n    ///     Moves to the next item.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public bool MoveNext()\r\n    {\r\n        return unchecked(--_index > 0);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Resets the enumerator.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        _index = _count+1;\r\n    }\r\n}\r\n/// <summary>\r\n///     The <see cref=\"UnsafeReverseEnumerator{T}\"/> is a basic implementation of the <see cref=\"IEnumerator{T}\"/> interface for iterating backwards.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic unsafe ref struct UnsafeReverseEnumerator<T> where T : unmanaged\r\n{\r\n    private readonly T* _list;\r\n    private readonly int _count;\r\n    private int _index;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeIEnumerator{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"list\">The <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"count\">Count.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal UnsafeReverseEnumerator(T* list, int count)\r\n    {\r\n        _list = list;\r\n        _count = count;\r\n        _index = count+1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the current item.\r\n    /// </summary>\r\n    public ref T Current => ref _list[_index-1];\r\n\r\n    /// <summary>\r\n    ///     Moves to the next item.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public bool MoveNext()\r\n    {\r\n        return unchecked(--_index > 0);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Resets the enumerator.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        _index = _count+1;\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel/Jagged/JaggedArray.cs",
    "content": "﻿using System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing CommunityToolkit.HighPerformance;\r\n\r\nnamespace Arch.LowLevel.Jagged;\r\n\r\n/// <summary>\r\n///     The <see cref=\"MathExtensions\"/>\r\n///     contains several methods for math operations.\r\n/// </summary>\r\ninternal static class MathExtensions\r\n{\r\n    /// <summary>\r\n    /// This method will round down to the nearest power of 2 number. If the supplied number is a power of 2 it will return it.\r\n    /// </summary>\r\n    /// <param name=\"num\"></param>\r\n    /// <returns></returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal static int RoundToPowerOfTwo(int num)\r\n    {\r\n        // If num is a power of 2, return it\r\n        if (num > 0 && (num & (num - 1)) == 0)\r\n        {\r\n            return num;\r\n        }\r\n\r\n        // Find the exponent of the nearest power of 2 (rounded down)\r\n        var exponent = (int)Math.Floor(Math.Log(num) / Math.Log(2));\r\n\r\n        // Calculate the nearest power of 2\r\n        var result = (int)Math.Pow(2, exponent);\r\n\r\n        return result;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"Bucket{T}\"/> struct\r\n///     represents a bucket of the <see cref=\"JaggedArray{T}\"/> where items are stored\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic record struct Bucket<T>\r\n{\r\n    /// <summary>\r\n    ///     The items array.\r\n    /// </summary>\r\n    internal readonly T[] Array = System.Array.Empty<T>();\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The capacity</param>\r\n    public Bucket(int capacity)\r\n    {\r\n        Array = new T[capacity];\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The amount of items in this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        internal set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this <see cref=\"Bucket{T}\"/> is empty.\r\n    /// </summary>\r\n    public bool IsEmpty\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count <= 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref Array.DangerousGetReferenceAt(i);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"Bucket{T}\"/> and sets all values to the <paramref name=\"filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear(T filler = default!)\r\n    {\r\n        System.Array.Fill(Array, filler);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"JaggedArray{T}\"/> class,\r\n///     represents a jagged array with <see cref=\"Bucket{T}\"/>s storing the items.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic class JaggedArray<T>\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items.\r\n    /// </summary>\r\n    private readonly int _bucketSize;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items - 1.\r\n    /// </summary>\r\n    private readonly int _bucketSizeMinusOne;\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"_bucketSize\"/> is always a value the power of 2, therefore we can use a bitshift for the division during the index calculation. \r\n    /// </summary>\r\n    private readonly int _bucketSizeShift;\r\n    \r\n    /// <summary>\r\n    ///     The allocated <see cref=\"Bucket{T}\"/>s.\r\n    /// </summary>\r\n    private Array<Bucket<T>> _buckets;\r\n\r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public JaggedArray(int bucketSize, int capacity = 64)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _buckets = new Array<Bucket<T>>(capacity/_bucketSize + 1);\r\n        \r\n        _filler = default!;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new Bucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"filler\">The filler value for all slots, basically a custom default-value.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public JaggedArray(int bucketSize, T filler, int capacity = 64) : this(bucketSize, capacity)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _buckets = new Bucket<T>[capacity/_bucketSize + 1];\r\n        \r\n        _filler = filler;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new Bucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The capacity, the total amount of items. \r\n    /// </summary>\r\n    public int Capacity => _buckets.Length * _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The length, the buckets inside the <see cref=\"_buckets\"/>.\r\n    /// </summary>\r\n    public int Buckets => _buckets.Length;\r\n\r\n    /// <summary>\r\n    ///     Adds an item to the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"item\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Add(int index, in T item)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = item;\r\n        bucket.Count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes an item from the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Remove(int index)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = _filler;\r\n        bucket.Count--;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"value\">The returned value.</param>\r\n    /// <returns>True if sucessfull, otherwhise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool TryGetValue(int index, out T value)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        value = item;\r\n        return true;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bool\">True if sucessfull, otherwhise false</param>\r\n    /// <returns>A reference or null reference to the item.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T TryGetValue(int index, out bool @bool)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n\r\n        @bool = true;\r\n        return ref item!; \r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if the value at the given index exists.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>True if it does, false if it does not.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool ContainsKey(int index)\r\n    {\r\n        if (index < 0 || index > Capacity)\r\n        {\r\n            return false;\r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        return !EqualityComparer<T>.Default.Equals(item, _filler);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity and increases it if necessary.\r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capcity.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity < Capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var length = Buckets;\r\n        var buckets = newCapacity / _bucketSize + 1;\r\n        _buckets = Array.Resize(ref _buckets, buckets);\r\n\r\n        for (var i = length; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new Bucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the last few empty buckets to release memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        // Count how many of the last buckets are empty, to trim them\r\n        var count = 0;\r\n        for (var i = _buckets.Length-1; i >= 0; i--)\r\n        {\r\n            ref var bucket = ref GetBucket(i);\r\n            if (!bucket.IsEmpty)\r\n            {\r\n                break;\r\n            }\r\n\r\n            count++;\r\n        }\r\n\r\n        var buckets = _buckets.Length-count;\r\n        _buckets = Array.Resize(ref _buckets, buckets);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts the passed id to its inner and outer index ( or slot ) inside the <see cref=\"_buckets\"/> array.\r\n    /// </summary>\r\n    /// <param name=\"id\">The id.</param>\r\n    /// <param name=\"bucketIndex\">The outer index.</param>\r\n    /// <param name=\"itemIndex\">The inner index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void IndexToSlot(int id, out int bucketIndex, out int itemIndex)\r\n    {\r\n        Debug.Assert(id >= 0, \"Id cannot be negative.\");\r\n\r\n        /* Instead of the '%' operator we can use logical '&' operator which is faster. But it requires the bucket size to be a power of 2. */\r\n        bucketIndex = id >> _bucketSizeShift;\r\n        itemIndex = id & _bucketSizeMinusOne;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the <see cref=\"Bucket{T}\"/> from the <see cref=\"_buckets\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>The <see cref=\"Bucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref Bucket<T> GetBucket(int index)\r\n    {\r\n        return ref _buckets[index];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Sets the <see cref=\"Bucket{T}\"/> of the <see cref=\"_buckets\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bucket\">The <see cref=\"Bucket{T}\"/> to set</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void SetBucket(int index, in Bucket<T> bucket)\r\n    {\r\n        _buckets[index] = bucket;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get\r\n        {\r\n            IndexToSlot(i, out var bucketIndex, out var itemIndex);\r\n            return ref GetBucket(bucketIndex)[itemIndex];\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"JaggedArray{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        foreach (var bucket in _buckets)\r\n        {\r\n            if (bucket.IsEmpty)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel/Jagged/SparseJaggedArray.cs",
    "content": "﻿using CommunityToolkit.HighPerformance;\r\n\r\nnamespace Arch.LowLevel.Jagged;\r\n\r\nusing System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\n\r\n/// <summary>\r\n///     The <see cref=\"SparseBucket{T}\"/> struct\r\n///     represents a bucket of the <see cref=\"SparseJaggedArray{T}\"/> where items are stored.\r\n///     <remarks>It will not allocate memory upon creation, it stays empty till the first item was added in.</remarks>\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic record struct SparseBucket<T>\r\n{\r\n    /// <summary>\r\n    ///     The items array.\r\n    /// </summary>\r\n    internal T[] Array = System.Array.Empty<T>();\r\n    \r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The total capacity.</param>\r\n    /// <param name=\"filler\">The filler.</param>\r\n    /// <param name=\"allocate\">If it should allocate straight forward.</param>\r\n    public SparseBucket(int capacity, T filler, bool allocate = false)\r\n    {\r\n        Capacity = capacity;\r\n        _filler = filler;\r\n        if (allocate)\r\n        {\r\n            EnsureCapacity();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The total capacity of this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Capacity\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n        \r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        private set;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The amount of items in this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        internal set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this <see cref=\"Bucket{T}\"/> is empty.\r\n    /// </summary>\r\n    public bool IsEmpty\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count <= 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the <see cref=\"Capacity\"/> of this <see cref=\"Bucket{T}\"/>.\r\n    ///     Basically allocated a new array. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void EnsureCapacity()\r\n    {\r\n        if (Array != System.Array.Empty<T>())\r\n        {\r\n            return;\r\n        }\r\n        \r\n        Array = new T[Capacity];\r\n        Clear();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the bucket to an empty one. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void TrimExcess()\r\n    {\r\n        if (Count > 0)\r\n        {\r\n            return;\r\n        }\r\n        \r\n        Array = System.Array.Empty<T>();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref Array.DangerousGetReferenceAt(i);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"SparseBucket{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        System.Array.Fill(Array, _filler);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"SparseJaggedArray{T}\"/> class,\r\n///     represents a jagged array with <see cref=\"SparseBucket{T}\"/>s storing the items.\r\n///     <remarks>Its buckets will stay empty and not allocate memory till a slot in it is being used.</remarks>\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic class SparseJaggedArray<T>\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items.\r\n    /// </summary>\r\n    private readonly int _bucketSize;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items - 1.\r\n    /// </summary>\r\n    private readonly int _bucketSizeMinusOne;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"_bucketSize\"/> is always a value the power of 2, therefore we can use a bitshift for the division during the index calculation. \r\n    /// </summary>\r\n    private readonly int _bucketSizeShift;\r\n\r\n    /// <summary>\r\n    ///     The allocated <see cref=\"Bucket{T}\"/>s.\r\n    /// </summary>\r\n    private Array<SparseBucket<T>> _buckets;\r\n\r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public SparseJaggedArray(int bucketSize, int capacity = 64)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _buckets = new Array<SparseBucket<T>>(capacity/_bucketSize + 1);\r\n        \r\n        _filler = default!;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new SparseBucket<T>(_bucketSize, _filler);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"filler\">The filler value for all slots, basically a custom default-value.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public SparseJaggedArray(int bucketSize, T filler, int capacity = 64) : this(bucketSize, capacity)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _buckets = new Array<SparseBucket<T>>(capacity/_bucketSize + 1);\r\n        \r\n        _filler = filler!;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new SparseBucket<T>(_bucketSize, filler);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     If true, each bucket will stay empty and will not allocate memory until its actually being used. \r\n    /// </summary>\r\n    public bool Sparse { get; set; }\r\n    \r\n    /// <summary>\r\n    ///     The capacity, the total amount of items. \r\n    /// </summary>\r\n    public int Capacity => _buckets.Length * _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The length, the buckets inside the <see cref=\"_buckets\"/>.\r\n    /// </summary>\r\n    public int Buckets => _buckets.Length;\r\n\r\n    /// <summary>\r\n    ///     Adds an item to the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"item\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Add(int index, in T item)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket.EnsureCapacity();\r\n        bucket[itemIndex] = item;\r\n        bucket.Count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes an item from the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Remove(int index)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = _filler;\r\n   \r\n        bucket.Count--;\r\n        bucket.TrimExcess();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"value\">The returned value.</param>\r\n    /// <returns>True if sucessfull, otherwhise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool TryGetValue(int index, out T value)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // Bucket empty? return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n        \r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        value = item;\r\n        return true;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bool\">True if sucessfull, otherwhise false</param>\r\n    /// <returns>A reference or null reference to the item.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T TryGetValue(int index, out bool @bool)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // Bucket empty? return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n        \r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n\r\n        @bool = true;\r\n        return ref item!; \r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the value at the given index exists.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>True if it does, false if it does not.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool ContainsKey(int index)\r\n    {\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            return false;\r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // If bucket empty return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            return false;\r\n        }\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        return !EqualityComparer<T>.Default.Equals(item, _filler);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity and increases it if necessary.\r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capcity.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity < Capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var length = Buckets;\r\n        var buckets = newCapacity / _bucketSize + 1;\r\n        _buckets = Array.Resize(ref _buckets, buckets);\r\n\r\n        for (var i = length; i < _buckets.Length; i++)\r\n        {\r\n            var bucket = new SparseBucket<T>(_bucketSize, _filler);\r\n            SetBucket(i, bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the last few empty buckets to release memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        // Count how many of the last buckets are empty, to trim them\r\n        var count = 0;\r\n        for (var i = _buckets.Length-1; i >= 0; i--)\r\n        {\r\n            ref var bucket = ref GetBucket(i);\r\n            if (!bucket.IsEmpty)\r\n            {\r\n                break;\r\n            }\r\n\r\n            count++;\r\n        }\r\n\r\n        var buckets = _buckets.Length-count;\r\n        _buckets = Array.Resize(ref _buckets, buckets);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts the passed id to its inner and outer index ( or slot ) inside the <see cref=\"_buckets\"/> array.\r\n    /// </summary>\r\n    /// <param name=\"id\">The id.</param>\r\n    /// <param name=\"bucketIndex\">The outer index.</param>\r\n    /// <param name=\"itemIndex\">The inner index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void IndexToSlot(int id, out int bucketIndex, out int itemIndex)\r\n    {\r\n        Debug.Assert(id >= 0, \"Id cannot be negative.\");\r\n\r\n        /* Instead of the '%' operator we can use logical '&' operator which is faster. But it requires the bucket size to be a power of 2. */\r\n        bucketIndex = id >> _bucketSizeShift;\r\n        itemIndex = id & _bucketSizeMinusOne;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the <see cref=\"SparseBucket{T}\"/> from the <see cref=\"_buckets\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>The <see cref=\"SparseBucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref SparseBucket<T> GetBucket(int index)\r\n    {\r\n        return ref _buckets[index];\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Sets the <see cref=\"SparseBucket{T}\"/> of the <see cref=\"_buckets\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bucket\">The <see cref=\"SparseBucket{T}\"/> to set</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void SetBucket(int index, in SparseBucket<T> bucket)\r\n    {\r\n        _buckets[index] = bucket;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get\r\n        {\r\n            IndexToSlot(i, out var bucketIndex, out var itemIndex);\r\n            return ref GetBucket(bucketIndex)[itemIndex];\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"SparseJaggedArray{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        foreach (var bucket in _buckets)\r\n        {\r\n            if (bucket.IsEmpty)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            bucket.Clear();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel/Jagged/UnsafeJaggedArray.cs",
    "content": "﻿using System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\n\r\nnamespace Arch.LowLevel.Jagged;\r\n\r\n/// <summary>\r\n///     The <see cref=\"Bucket{T}\"/> struct\r\n///     represents a bucket of the <see cref=\"JaggedArray{T}\"/> where items are stored\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic record struct UnsafeBucket<T> : IDisposable where T : unmanaged\r\n{\r\n    /// <summary>\r\n    ///     The items array.\r\n    /// </summary>\r\n    internal UnsafeArray<T> Array = UnsafeArray.Empty<T>();\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The capacity</param>\r\n    public UnsafeBucket(int capacity)\r\n    {\r\n        Array = new UnsafeArray<T>(capacity);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The amount of items in this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        internal set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this <see cref=\"Bucket{T}\"/> is empty.\r\n    /// </summary>\r\n    public bool IsEmpty\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count <= 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref Array[i];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Clears this <see cref=\"UnsafeBucket{T}\"/> and sets all values to the <paramref name=\"filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear(T filler = default)\r\n    {\r\n        UnsafeArray.Fill(ref Array, filler);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"UnsafeBucket{T}\"/>. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        Array.Dispose();\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeJaggedArray{T}\"/> class,\r\n///     represents a jagged array with <see cref=\"UnsafeBucket{T}\"/>s storing the items.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic struct UnsafeJaggedArray<T> : IDisposable where T : unmanaged\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items.\r\n    /// </summary>\r\n    private readonly int _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items - 1.\r\n    /// </summary>\r\n    private readonly int _bucketSizeMinusOne;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"_bucketSize\"/> is always a value the power of 2, therefore we can use a bitshift for the division during the index calculation. \r\n    /// </summary>\r\n    private readonly int _bucketSizeShift;\r\n\r\n    /// <summary>\r\n    ///     The allocated <see cref=\"Bucket{T}\"/>s.\r\n    /// </summary>\r\n    private UnsafeArray<UnsafeBucket<T>> _bucketArray;\r\n\r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public UnsafeJaggedArray(int bucketSize, int capacity = 64)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _bucketArray = new UnsafeArray<UnsafeBucket<T>>(capacity / _bucketSize + 1);\r\n\r\n        _filler = default!;\r\n        \r\n        // Fill buckets\r\n        for (var i = 0; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeBucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"filler\">The filler value for all slots, basically a custom default-value.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public UnsafeJaggedArray(int bucketSize, T filler, int capacity = 64)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _bucketArray = new UnsafeArray<UnsafeBucket<T>>(capacity / _bucketSize + 1);\r\n\r\n        _filler = filler;\r\n        \r\n        // Fill buckets\r\n        for (var i = 0; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeBucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The capacity, the total amount of items. \r\n    /// </summary>\r\n    public int Capacity => _bucketArray.Length * _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The length, the buckets inside the <see cref=\"_bucketArray\"/>.\r\n    /// </summary>\r\n    public int Buckets => _bucketArray.Length;\r\n\r\n    /// <summary>\r\n    ///     Adds an item to the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"item\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Add(int index, in T item)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = item;\r\n        bucket.Count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes an item from the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Remove(int index)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = _filler;\r\n        bucket.Count--;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"value\">The returned value.</param>\r\n    /// <returns>True if sucessfull, otherwhise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool TryGetValue(int index, out T value)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity )\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n        \r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        value = item;\r\n        return true;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bool\">True if sucessfull, otherwhise false</param>\r\n    /// <returns>A reference or null reference to the item.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T TryGetValue(int index, out bool @bool)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n\r\n        @bool = true;\r\n        return ref item; \r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if the value at the given index exists.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>True if it does, false if it does not.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool ContainsKey(int index)\r\n    {\r\n        if (index < 0 || index > Capacity)\r\n        {\r\n            return false;\r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        ref var item = ref GetBucket(bucketIndex)[itemIndex];\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        return !EqualityComparer<T>.Default.Equals(item, _filler);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity and increases it if necessary.\r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capcity.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity < Capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var length = Buckets;\r\n        var buckets = newCapacity / _bucketSize + 1;\r\n        _bucketArray = UnsafeArray.Resize(ref _bucketArray, buckets);\r\n\r\n        for (var i = length; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeBucket<T>(_bucketSize);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the last few empty buckets to release memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        // Count how many of the last buckets are empty, to trim them\r\n        var count = 0;\r\n        for (var i = _bucketArray.Length - 1; i >= 0; i--)\r\n        {\r\n            ref var bucket = ref _bucketArray[i];\r\n            if (!bucket.IsEmpty)\r\n            {\r\n                break;\r\n            }\r\n\r\n            count++;\r\n        }\r\n\r\n        var buckets = _bucketArray.Length - count;\r\n        _bucketArray = UnsafeArray.Resize(ref _bucketArray, buckets);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts the passed id to its inner and outer index ( or slot ) inside the <see cref=\"_bucketArray\"/> array.\r\n    /// </summary>\r\n    /// <param name=\"id\">The id.</param>\r\n    /// <param name=\"bucketIndex\">The outer index.</param>\r\n    /// <param name=\"itemIndex\">The inner index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void IndexToSlot(int id, out int bucketIndex, out int itemIndex)\r\n    {\r\n        Debug.Assert(id >= 0, \"Id cannot be negative.\");\r\n\r\n        /* Instead of the '%' operator we can use logical '&' operator which is faster. But it requires the bucket size to be a power of 2. */\r\n        bucketIndex = id >> _bucketSizeShift;\r\n        itemIndex = id & _bucketSizeMinusOne;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the <see cref=\"UnsafeBucket{T}\"/> from the <see cref=\"_bucketArray\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>The <see cref=\"UnsafeBucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref UnsafeBucket<T> GetBucket(int index)\r\n    {\r\n        return ref _bucketArray[index];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Sets the <see cref=\"UnsafeBucket{T}\"/> from the <see cref=\"_bucketArray\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bucket\">Bucket.</param>\r\n    /// <returns>The <see cref=\"UnsafeBucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void SetBucket(int index, in UnsafeBucket<T> bucket)\r\n    {\r\n        _bucketArray[index] = bucket;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get\r\n        {\r\n            IndexToSlot(i, out var bucketIndex, out var itemIndex);\r\n            return ref GetBucket(bucketIndex)[itemIndex];\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"JaggedArray{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        foreach (ref var bucket in _bucketArray)\r\n        {\r\n            if (bucket.IsEmpty)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            bucket.Clear(_filler);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"UnsafeJaggedArray{T}\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        foreach (ref var bucket in _bucketArray)\r\n        {\r\n            bucket.Dispose();\r\n        }\r\n        _bucketArray.Dispose();\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.LowLevel/Jagged/UnsafeSparseJaggedArray.cs",
    "content": "﻿using System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\n\r\nnamespace Arch.LowLevel.Jagged;\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeSparseBucket{T}\"/> struct\r\n///     represents a bucket of the <see cref=\"UnsafeSparseJaggedArray{T}\"/> where items are stored.\r\n///     <remarks>It will not allocate memory upon creation, it stays empty till the first item was added in.</remarks>\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic record struct UnsafeSparseBucket<T> : IDisposable where T : unmanaged\r\n{\r\n    \r\n    /// <summary>\r\n    ///     The items array.\r\n    /// </summary>\r\n    internal UnsafeArray<T> Array = UnsafeArray.Empty<T>();\r\n    \r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The total capacity.</param>\r\n    /// <param name=\"filler\">The filler.</param>\r\n    /// <param name=\"allocate\">If it should allocate straight forward.</param>\r\n    public UnsafeSparseBucket(int capacity, T filler, bool allocate = false)\r\n    {\r\n        Capacity = capacity;\r\n        _filler = filler;\r\n        if (allocate)\r\n        {\r\n            EnsureCapacity();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The total capacity of this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Capacity\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n        \r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        private set;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The amount of items in this <see cref=\"Bucket{T}\"/>.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        internal set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this <see cref=\"Bucket{T}\"/> is empty.\r\n    /// </summary>\r\n    public bool IsEmpty\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count <= 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the <see cref=\"Capacity\"/> of this <see cref=\"Bucket{T}\"/>.\r\n    ///     Basically allocated a new array. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void EnsureCapacity()\r\n    {\r\n        if (Array != UnsafeArray.Empty<T>())\r\n        {\r\n            return;\r\n        }\r\n        \r\n        Array = new UnsafeArray<T>(Capacity);\r\n        Clear();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the bucket to an empty one. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void TrimExcess()\r\n    {\r\n        if (Count > 0)\r\n        {\r\n            return;\r\n        }\r\n        \r\n        Array = UnsafeArray.Empty<T>();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref Array[i];\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"UnsafeSparseBucket{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        UnsafeArray.Fill(ref Array, _filler);\r\n    }\r\n\r\n\r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"UnsafeSparseBucket{T}\"/>\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        Array.Dispose();\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeSparseJaggedArray{T}\"/> class,\r\n///     represents a jagged array with <see cref=\"SparseBucket{T}\"/>s storing the items.\r\n///     <remarks>Its buckets will stay empty and not allocate memory till a slot in it is being used.</remarks>\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic struct UnsafeSparseJaggedArray<T> : IDisposable where T : unmanaged\r\n{\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items.\r\n    /// </summary>\r\n    private readonly int _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"Bucket{T}\"/> size in items - 1.\r\n    /// </summary>\r\n    private readonly int _bucketSizeMinusOne;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"_bucketSize\"/> is always a value the power of 2, therefore we can use a bitshift for the division during the index calculation. \r\n    /// </summary>\r\n    private readonly int _bucketSizeShift;\r\n\r\n    /// <summary>\r\n    ///     The allocated <see cref=\"Bucket{T}\"/>s.\r\n    /// </summary>\r\n    private UnsafeArray<UnsafeSparseBucket<T>> _bucketArray;\r\n\r\n    /// <summary>\r\n    ///     The filler, the default value.\r\n    /// </summary>\r\n    private readonly T _filler;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public UnsafeSparseJaggedArray(int bucketSize, int capacity = 64)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _bucketArray = new UnsafeArray<UnsafeSparseBucket<T>>(capacity / _bucketSize + 1);\r\n\r\n        _filler = default!;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeSparseBucket<T>(_bucketSize, _filler);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"bucketSize\">The <see cref=\"Bucket{T}\"/> size in bytes.</param>\r\n    /// <param name=\"filler\">The filler value for all slots, basically a custom default-value.</param>\r\n    /// <param name=\"capacity\">The total initial capacity, how many items should fit in.</param>\r\n    public UnsafeSparseJaggedArray(int bucketSize, T filler, int capacity = 64) : this(bucketSize, capacity)\r\n    {\r\n        _bucketSize = MathExtensions.RoundToPowerOfTwo(bucketSize);\r\n        _bucketSizeMinusOne = _bucketSize - 1;\r\n        _bucketSizeShift = (int)Math.Log(_bucketSize, 2);\r\n        _bucketArray = new UnsafeArray<UnsafeSparseBucket<T>>(capacity / _bucketSize + 1);\r\n\r\n        _filler = filler!;\r\n\r\n        // Fill buckets\r\n        for (var i = 0; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeSparseBucket<T>(_bucketSize, _filler);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If true, each bucket will stay empty and will not allocate memory until its actually being used. \r\n    /// </summary>\r\n    public bool Sparse { get; set; }\r\n\r\n    /// <summary>\r\n    ///     The capacity, the total amount of items. \r\n    /// </summary>\r\n    public int Capacity => _bucketArray.Length * _bucketSize;\r\n\r\n    /// <summary>\r\n    ///     The length, the buckets inside the <see cref=\"_bucketArray\"/>.\r\n    /// </summary>\r\n    public int Buckets => _bucketArray.Length;\r\n\r\n    /// <summary>\r\n    ///     Adds an item to the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"item\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Add(int index, in T item)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket.EnsureCapacity();\r\n        bucket[itemIndex] = item;\r\n        bucket.Count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes an item from the <see cref=\"JaggedArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Remove(int index)\r\n    {\r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        bucket[itemIndex] = _filler;\r\n\r\n        bucket.Count--;\r\n        bucket.TrimExcess();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"value\">The returned value.</param>\r\n    /// <returns>True if sucessfull, otherwhise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool TryGetValue(int index, out T value)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // Bucket empty? return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            value = _filler;\r\n            return false;\r\n        }\r\n\r\n        value = item;\r\n        return true;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trys to get an item from its index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bool\">True if sucessfull, otherwhise false</param>\r\n    /// <returns>A reference or null reference to the item.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T TryGetValue(int index, out bool @bool)\r\n    {\r\n        // If the id is negative\r\n        if (index < 0 || index >= Capacity)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n        \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // Bucket empty? return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n        \r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        if (EqualityComparer<T>.Default.Equals(item, _filler))\r\n        {\r\n            @bool = false;\r\n            return ref Unsafe.NullRef<T>(); \r\n        }\r\n\r\n        @bool = true;\r\n        return ref item; \r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the value at the given index exists.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>True if it does, false if it does not.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool ContainsKey(int index)\r\n    {\r\n        if (index < 0 || index > Capacity)\r\n        {\r\n            return false;\r\n        }\r\n    \r\n        IndexToSlot(index, out var bucketIndex, out var itemIndex);\r\n        \r\n        // If bucket empty return false\r\n        ref var bucket = ref GetBucket(bucketIndex);\r\n        if (bucket.IsEmpty)\r\n        {\r\n            return false;\r\n        }\r\n\r\n        // If the item is the default then the nobody set its value.\r\n        ref var item = ref bucket[itemIndex];\r\n        return !EqualityComparer<T>.Default.Equals(item, _filler);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity and increases it if necessary.\r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capcity.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity < Capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var length = Buckets;\r\n        var buckets = newCapacity / _bucketSize + 1;\r\n        _bucketArray = UnsafeArray.Resize(ref _bucketArray, buckets);\r\n\r\n        for (var i = length; i < _bucketArray.Length; i++)\r\n        {\r\n            var bucket = new UnsafeSparseBucket<T>(_bucketSize, _filler);\r\n            SetBucket(i, in bucket);\r\n            bucket.Clear();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the last few empty buckets to release memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        // Count how many of the last buckets are empty, to trim them\r\n        var count = 0;\r\n        for (var i = _bucketArray.Length - 1; i >= 0; i--)\r\n        {\r\n            ref var bucket = ref _bucketArray[i];\r\n            if (!bucket.IsEmpty)\r\n            {\r\n                break;\r\n            }\r\n\r\n            count++;\r\n        }\r\n\r\n        var buckets = _bucketArray.Length - count;\r\n        _bucketArray = UnsafeArray.Resize(ref _bucketArray, buckets);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts the passed id to its inner and outer index ( or slot ) inside the <see cref=\"_bucketArray\"/> array.\r\n    /// </summary>\r\n    /// <param name=\"id\">The id.</param>\r\n    /// <param name=\"bucketIndex\">The outer index.</param>\r\n    /// <param name=\"itemIndex\">The inner index.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void IndexToSlot(int id, out int bucketIndex, out int itemIndex)\r\n    {\r\n        Debug.Assert(id >= 0, \"Id cannot be negative.\");\r\n\r\n        /* Instead of the '%' operator we can use logical '&' operator which is faster. But it requires the bucket size to be a power of 2. */\r\n        bucketIndex = id >> _bucketSizeShift;\r\n        itemIndex = id & _bucketSizeMinusOne;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the <see cref=\"UnsafeSparseBucket{T}\"/> from the <see cref=\"_bucketArray\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <returns>The <see cref=\"UnsafeSparseBucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref UnsafeSparseBucket<T> GetBucket(int index)\r\n    {\r\n        return ref _bucketArray[index];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Sets the <see cref=\"UnsafeSparseBucket{T}\"/> from the <see cref=\"_bucketArray\"/> at the given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"bucket\">Bucket.</param>\r\n    /// <returns>The <see cref=\"UnsafeSparseBucket{T}\"/> at the given index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void SetBucket(int index, in UnsafeSparseBucket<T> bucket)\r\n    {\r\n        _bucketArray[index] = bucket;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a reference to an item at the given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get\r\n        {\r\n            IndexToSlot(i, out var bucketIndex, out var itemIndex);\r\n            return ref GetBucket(bucketIndex)[itemIndex];\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Clears this <see cref=\"UnsafeSparseJaggedArray{T}\"/> and sets all values to the <see cref=\"_filler\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        foreach (ref var bucket in _bucketArray)\r\n        {\r\n            if (bucket.IsEmpty)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            UnsafeArray.Fill(ref bucket.Array, _filler);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"UnsafeSparseJaggedArray{T}\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        foreach (ref var bucket in _bucketArray)\r\n        {\r\n            bucket.Dispose();\r\n        }\r\n        _bucketArray.Dispose();\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel/Resources.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing Arch.LowLevel.Jagged;\r\n\r\n[assembly: InternalsVisibleTo(\"Arch.LowLevel.Tests\")]\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The <see cref=\"Handle{T}\"/> struct\r\n///     represents a reference to an managed resource.\r\n///     This is used commonly for referencing managed resources from components.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The type of the managed resource.</typeparam>\r\npublic readonly record struct Handle<T>\r\n{\r\n    \r\n    /// <summary>\r\n    ///     A null <see cref=\"Handle{T}\"/> which is invalid and used for camparison.\r\n    /// </summary>\r\n    public static readonly Handle<T> NULL = new(-1);\r\n    \r\n    /// <summary>\r\n    ///     The id, its index inside a <see cref=\"Resources{T}\"/> array.\r\n    /// </summary>\r\n    public readonly int Id = -1;\r\n\r\n    /// <summary>\r\n    ///     Public default constructor.\r\n    /// </summary>\r\n    public Handle()\r\n    {\r\n        Id = -1;\r\n    }\r\n\r\n    /// <summary>\r\n    ///      Initializes a new instance of the <see cref=\"Handle{T}\" /> class.\r\n    /// </summary>\r\n    /// <param name=\"id\"></param>\r\n    internal Handle(int id)\r\n    {\r\n        Id = id;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"Handle{T}\"/> class,\r\n///     represents an collection of managed resources which can be accesed by a <see cref=\"Handle{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\"></typeparam>\r\npublic sealed class Resources<T> : IDisposable\r\n{\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"JaggedArray{T}\"/> which stores the managed resources on the <see cref=\"Handle{T}\"/> index.\r\n    /// </summary>\r\n    private JaggedArray<T> _array;\r\n\r\n    /// <summary>\r\n    ///     A list of recycled <see cref=\"Handle{T}\"/> ids, used to fill in old gaps.\r\n    /// </summary>\r\n    internal Queue<int> _ids;\r\n\r\n    /// <summary>\r\n    ///     Creates an <see cref=\"Resources{T}\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The capacity of the bucket.</param>\r\n    public Resources(int capacity = 64)\r\n    {\r\n        _array = new JaggedArray<T>(capacity, capacity);\r\n        _ids = new Queue<int>(capacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an <see cref=\"Resources{T}\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"size\">The size of the generic type in bytes.</param>\r\n    /// <param name=\"capacity\">The capcity, how many items of that type should fit into the array.</param>\r\n    public Resources(int size, int capacity = 64)\r\n    {\r\n        _array = new JaggedArray<T>(160000/size, capacity);\r\n        _ids = new Queue<int>(capacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The amount of registered <see cref=\"Handle{T}\"/>s.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        private set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates a <see cref=\"Handle{T}\"/> for the given resource.\r\n    /// </summary>\r\n    /// <param name=\"item\">The resource instance.</param>\r\n    /// <returns></returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Handle<T> Add(in T item)\r\n    {\r\n        // Create handle\r\n        var recyled = _ids.TryDequeue(out var id);\r\n        id = recyled ? id : Count;\r\n        var handle = new Handle<T>(id);\r\n\r\n        // Resize array and fill it in\r\n        _array.EnsureCapacity(id+1);\r\n        _array.Add(id, item);\r\n\r\n        Count++;\r\n        return handle;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the <see cref=\"Handle{T}\"/> is valid.\r\n    /// </summary>\r\n    /// <param name=\"handle\">The <see cref=\"Handle{T}\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool IsValid(in Handle<T> handle)\r\n    {\r\n        return handle.Id > -1 && handle.Id <= _array.Capacity;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a resource for the given <see cref=\"Handle{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"handle\">The <see cref=\"Handle{T}\"/>.</param>\r\n    /// <returns>The resource.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T Get(in Handle<T> handle)\r\n    {\r\n        return ref _array[handle.Id];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes a <see cref=\"Handle{T}\"/> and its resource.\r\n    /// </summary>\r\n    /// <param name=\"handle\">The <see cref=\"Handle{T}\"/>.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Remove(in Handle<T> handle)\r\n    {\r\n        _array.Remove(handle.Id);\r\n        _ids.Enqueue(handle.Id);\r\n\r\n        Count--;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the resources and releases unused memory if possible.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        _array.TrimExcess();\r\n        _ids.TrimExcess();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"Resources{T}\"/> instance.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        _array = null!;\r\n        _ids = null!;\r\n        Count = 0;\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.LowLevel/UnsafeArray.cs",
    "content": "﻿using System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing System.Text;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The <see cref=\"UnsafeArray{T}\"/> struct\r\n///     represents an unsafe allocated array of unmanaged items.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged generic.</typeparam>\r\n[DebuggerTypeProxy(typeof(UnsafeArrayDebugView<>))]\r\npublic readonly unsafe struct UnsafeArray<T> : IDisposable where T : unmanaged\r\n{\r\n\r\n    /// <summary>\r\n    ///     The static empty <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    internal static UnsafeArray<T> Empty = new(null, 0);\r\n    \r\n    /// <summary>\r\n    ///     The pointer, pointing towards the first element of this <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    internal readonly T* _ptr;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeArray{T}\"/>.\r\n    ///     Allocates the array for the passed count of items.\r\n    /// </summary>\r\n    /// <param name=\"count\">The arrays count or capacity.</param>\r\n    public UnsafeArray(int count)\r\n    {\r\n#if NET6_0_OR_GREATER\r\n        _ptr = (T*)NativeMemory.Alloc((nuint)(sizeof(T) * count));\r\n#else\r\n        _ptr = (T*)Marshal.AllocHGlobal(sizeof(T) * count);\r\n#endif\r\n        Count = count;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeArray{T}\"/> by a pointer.\r\n    /// </summary>\r\n    /// <param name=\"ptr\">The pointer.</param>\r\n    /// <param name=\"count\">The count.</param>\r\n    public UnsafeArray(T* ptr, int count)\r\n    {\r\n        _ptr = ptr;\r\n        Count = count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The count of this <see cref=\"UnsafeArray{T}\"/> instance, its capacity.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The count of this <see cref=\"UnsafeArray{T}\"/> instance, its capacity.\r\n    /// </summary>\r\n    public int Length\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns a reference to an item at a given index.\r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref _ptr[i];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Disposes this instance of <see cref=\"UnsafeArray{T}\"/> and releases its memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n#if NET6_0_OR_GREATER\r\n        NativeMemory.Free(_ptr);\r\n#else\r\n        Marshal.FreeHGlobal((IntPtr)_ptr);\r\n#endif\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeArray{T}\"/> instance into a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>A new instance of <see cref=\"Span{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Span<T> AsSpan()\r\n    {\r\n        return new Span<T>(_ptr, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"UnsafeEnumerator{T}\"/> for ref acessing the array content.\r\n    /// </summary>\r\n    /// <returns>A new <see cref=\"UnsafeEnumerator{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public UnsafeEnumerator<T> GetEnumerator()\r\n    {\r\n        return new UnsafeEnumerator<T>(_ptr, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"other\">The other <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns>True if equal, oterwhise false.</returns>\r\n    public bool Equals(UnsafeArray<T> other)\r\n    {\r\n        return _ptr == other._ptr && Count == other.Count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"obj\">The other <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns>True if equal, oterwhise false.</returns>\r\n    public override bool Equals(object? obj)\r\n    {\r\n        return obj is UnsafeArray<T> other && Equals(other);\r\n    }\r\n\r\n    \r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns></returns>\r\n    public static bool operator ==(UnsafeArray<T> left, UnsafeArray<T> right)\r\n    {\r\n        return left.Equals(right);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for inequality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeArray\"/>.</param>\r\n    /// <returns></returns>\r\n    public static bool operator !=(UnsafeArray<T> left, UnsafeArray<T> right)\r\n    {\r\n        return !left.Equals(right);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the hash of this <see cref=\"UnsafeArray\"/>.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public override int GetHashCode()\r\n    {\r\n        unchecked\r\n        {\r\n            return (unchecked((int)(long)_ptr) * 397) ^ Count;\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts an <see cref=\"UnsafeArray{T}\"/> into a void pointer.\r\n    /// </summary>\r\n    /// <param name=\"instance\">The <see cref=\"UnsafeArray{T}\"/> instance.</param>\r\n    /// <returns>A void pointer.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static implicit operator void*(UnsafeArray<T> instance)\r\n    {\r\n        return (void*)instance._ptr;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts an <see cref=\"UnsafeArray{T}\"/> into a generic pointer.\r\n    /// </summary>\r\n    /// <param name=\"instance\">The <see cref=\"UnsafeArray{T}\"/> instance.</param>\r\n    /// <returns>A void pointer.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static implicit operator T*(UnsafeArray<T> instance)\r\n    {\r\n        return instance._ptr;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeArray{T}\"/> to a string.\r\n    /// </summary>\r\n    /// <returns>The string.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public override string ToString()\r\n    {\r\n        var items = new StringBuilder();\r\n        foreach (ref var item in this)\r\n        {\r\n            items.Append($\"{item},\");\r\n        }\r\n        items.Length--;\r\n        return $\"UnsafeArray<{typeof(T).Name}>[{Count}]{{{items}}}\";\r\n    }\r\n}\r\n\r\n/// <summary>\r\n/// Unsafe array.\r\n/// </summary>\r\npublic unsafe struct UnsafeArray\r\n{\r\n\r\n    /// <summary>\r\n    ///     Returns an empty <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The generic type.</typeparam>\r\n    /// <returns>The empty <see cref=\"UnsafeArray{T}\"/>.</returns>\r\n    public static UnsafeArray<T> Empty<T>() where T : unmanaged\r\n    {\r\n        return UnsafeArray<T>.Empty;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///  Copies the a part of the <see cref=\"UnsafeArray{T}\"/> to the another <see cref=\"UnsafeArray{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"source\">The source <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"index\">The start index in the source <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"destination\">The destination <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"destinationIndex\">The start index in the destination <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"length\">The length indicating the amount of items being copied.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void Copy<T>(ref UnsafeArray<T> source, int index, ref UnsafeArray<T> destination, int destinationIndex, int length) where T : unmanaged\r\n    {\r\n        var size = sizeof(T);\r\n        var bytes = size * length;\r\n        var sourcePtr = (void*)(source._ptr + index);\r\n        var destinationPtr = (void*)(destination._ptr + destinationIndex);\r\n        Buffer.MemoryCopy(sourcePtr, destinationPtr, bytes, bytes);\r\n    }\r\n\r\n\r\n    /// <summary>\r\n    ///     Fills an <see cref=\"UnsafeArray{T}\"/> with a given value.\r\n    /// </summary>\r\n    /// <param name=\"source\">The <see cref=\"UnsafeArray{T}\"/> instance.</param>\r\n    /// <param name=\"value\">The value.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void Fill<T>(ref UnsafeArray<T> source, in T value = default) where T : unmanaged\r\n    {\r\n        source.AsSpan().Fill(value);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Resizes an <see cref=\"UnsafeArray{T}\"/> to a new <paramref name=\"newCapacity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"source\">The <see cref=\"UnsafeArray{T}\"/>.</param>\r\n    /// <param name=\"newCapacity\">The new capacity.</param>\r\n    /// <typeparam name=\"T\">The generic type.</typeparam>\r\n    /// <returns>The new resized <see cref=\"UnsafeArray{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static UnsafeArray<T> Resize<T>(ref UnsafeArray<T> source, int newCapacity) where T : unmanaged\r\n    {\r\n        var destination = new UnsafeArray<T>(newCapacity);\r\n        Copy(ref source, 0, ref destination, 0, Math.Min(source.Length, destination.Length));\r\n\r\n        source.Dispose();\r\n        return destination;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     A debug view for the <see cref=\"UnsafeArray{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged type.</typeparam>\r\ninternal class UnsafeArrayDebugView<T> where T : unmanaged\r\n{\r\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\r\n    private readonly UnsafeArray<T> _entity;\r\n\r\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\r\n    public T[] Items\r\n    {\r\n        get\r\n        {\r\n            var items = new T[_entity.Count];\r\n            _entity.AsSpan().CopyTo(items);\r\n            return items;\r\n        }\r\n    }\r\n\r\n    public UnsafeArrayDebugView(UnsafeArray<T> entity) => _entity = entity;\r\n}"
  },
  {
    "path": "Arch.LowLevel/UnsafeList.cs",
    "content": "﻿using System.Collections;\r\nusing System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Text;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The struct <see cref=\"UnsafeList{T}\"/> represents a native unmanaged list.\r\n///     Can easily be stored in unmanaged structs. \r\n/// </summary>\r\n/// <typeparam name=\"T\">The generic type stored in the list.</typeparam>\r\n[DebuggerTypeProxy(typeof(UnsafeListDebugView<>))]\r\npublic unsafe struct UnsafeList<T> : IList<T>, IDisposable where T : unmanaged\r\n{\r\n    /// <summary>\r\n    ///     The array pointer.\r\n    /// </summary>\r\n    private UnsafeArray<T> _array;\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeList{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The initial capacity that is being allocated.</param>\r\n    public UnsafeList(int capacity = 8)\r\n    {\r\n        Count = 0;\r\n        Capacity = capacity;\r\n        _array = new UnsafeArray<T>(capacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeList{T}\"/> by a pointer.\r\n    /// </summary>\r\n    /// <param name=\"ptr\">The pointer.</param>\r\n    /// <param name=\"capacity\">The initial capacity that is being allocated.</param>\r\n    public UnsafeList(T* ptr, int capacity = 8)\r\n    {\r\n        Count = 0;\r\n        Capacity = capacity;\r\n        _array = new UnsafeArray<T>(ptr, capacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The amount of items in the list.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get; \r\n        \r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        private set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The total capacity of this list.\r\n    /// </summary>\r\n    public int Capacity\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get; \r\n        \r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        private set;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If its readonly.\r\n    /// </summary>\r\n    public bool IsReadOnly\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds an item to the list.\r\n    /// </summary>\r\n    /// <param name=\"item\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Add(T item)\r\n    {\r\n        if (Count == Capacity)\r\n        {\r\n            EnsureCapacity(Capacity * 2);\r\n        }\r\n\r\n        _array[Count] = item;\r\n        Count++;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Inserts an item at the given index. \r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <param name=\"item\">The item instance.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Insert(int index, T item)\r\n    {\r\n        // Inserting to end of the list is legal.\r\n        if ((uint)index > (uint)Count)\r\n        {\r\n            throw new ArgumentOutOfRangeException(nameof(index)); \r\n        }\r\n        \r\n        // Resize if the list is actually full\r\n        if (Capacity == Count) \r\n        {\r\n            EnsureCapacity(Capacity + 1);\r\n        }\r\n\r\n        if (index < Count)\r\n        {\r\n            //var span = _array.AsSpan();\r\n            //var src = span.Slice(index, Count - index);\r\n            //var dst = span.Slice(index + 1, src.Length);\r\n            //src.CopyTo(dst);\r\n\r\n            UnsafeArray.Copy(ref _array, index, ref _array, index + 1, Count - index);\r\n        }\r\n        \r\n        _array[index] = item;\r\n        Count++;\r\n    }\r\n\r\n\r\n    /// <summary>\r\n    ///     Removes an item from the list at a given index.\r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    /// <exception cref=\"ArgumentOutOfRangeException\">Throws when the index is out of range.</exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void RemoveAt(int index)\r\n    {\r\n        if ((uint)index > (uint)Count) \r\n        {\r\n            throw new ArgumentOutOfRangeException(nameof(index));\r\n        }\r\n        \r\n        Count--;\r\n        if (index < Count) \r\n        {\r\n            //Buffer.MemoryCopy(_array+(index+1), _array+index,Count-index,Count-index);\r\n            UnsafeArray.Copy(ref _array, index + 1, ref _array, index, Count - index);\r\n        }\r\n        _array[Count] = default;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes the item by its value and returns true or false.\r\n    /// </summary>\r\n    /// <param name=\"item\">The item.</param>\r\n    /// <returns>True if the operation was sucessfull, false if it was not.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool Remove(T item)\r\n    {\r\n        var index = IndexOf(item);\r\n        if (index < 0) return false;\r\n        \r\n        RemoveAt(index);\r\n        return true;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if the item is containted in this <see cref=\"UnsafeList{T}\"/> instance and returns its index.\r\n    /// </summary>\r\n    /// <param name=\"item\">The item.</param>\r\n    /// <returns>Its index.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public int IndexOf(T item)\r\n    {\r\n        for(var i = 0; i < Count; i++) \r\n        {\r\n            if(EqualityComparer<T>.Default.Equals(_array[i], item)) \r\n            {\r\n                return i;\r\n            }\r\n        }\r\n        return -1;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if the item is containted in this <see cref=\"UnsafeList{T}\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"item\">The item.</param>\r\n    /// <returns>True if it exists, otherwhise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool Contains(T item)\r\n    {\r\n        for(var i = 0; i < Count; i++) \r\n        {\r\n            if(EqualityComparer<T>.Default.Equals(_array[i], item)) \r\n            {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Copies all items from this <see cref=\"UnsafeList{T}\"/> to the specified array.\r\n    /// </summary>\r\n    /// <param name=\"array\">The array to copy to.</param>\r\n    /// <param name=\"arrayIndex\">The index to start with.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void CopyTo(T[] array, int arrayIndex)\r\n    {\r\n        if (Count == 0)\r\n            return;\r\n        if (arrayIndex < 0 || arrayIndex >= array.Length)\r\n            throw new IndexOutOfRangeException(\"Index must be 0 <= index <= array.Length\");\r\n        if (arrayIndex + Count > array.Length)\r\n            throw new ArgumentException(\"Destination array was not long enough. Check the destination index, length, and the array's lower bounds.\", nameof(arrayIndex));\r\n\r\n        fixed(T* arrayPtr = array)\r\n        {\r\n            Buffer.MemoryCopy(_array, arrayPtr+arrayIndex, array.Length * sizeof(T), Count * sizeof(T));\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity of this <see cref=\"UnsafeList{T}\"/> instance and resizes it accordingly.\r\n    /// </summary>\r\n    /// <param name=\"min\">The minimum amount of items ensured.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int min)\r\n    {\r\n        if (min <= Count)\r\n        {\r\n            return;\r\n        }\r\n        \r\n        var oldArray = _array;\r\n        var newArray = new UnsafeArray<T>(min);\r\n        \r\n        // Copy & Free\r\n        UnsafeArray.Copy(ref oldArray, 0, ref newArray,0, Count);\r\n        oldArray.Dispose();\r\n\r\n        _array = newArray;\r\n        Capacity = min;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trims the capacity of this <see cref=\"UnsafeList{T}\"/> to release unused memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        var oldArray = _array;\r\n        var newArray = new UnsafeArray<T>(Count);\r\n        \r\n        // Copy & free\r\n        UnsafeArray.Copy(ref oldArray, 0, ref newArray,0, Count);\r\n        oldArray.Dispose();\r\n        \r\n        _array = newArray;\r\n        Capacity = Count;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///    Acesses an item at the index of the list. \r\n    /// </summary>\r\n    /// <param name=\"index\">The index.</param>\r\n    T IList<T>.this[int index]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _array[CheckIndex(index)];\r\n        \r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        set => _array[CheckIndex(index)] = value;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Acesses an item at the index of the list. \r\n    /// </summary>\r\n    /// <param name=\"i\">The index.</param>\r\n    public ref T this[int i]\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ref _array[CheckIndex(i)];\r\n    }\r\n\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    private readonly int CheckIndex(int index)\r\n    {\r\n#if DEBUG\r\n        if (index < 0)\r\n            throw new IndexOutOfRangeException(\"Index cannot be less than zero\");\r\n        if (index >= Count)\r\n            throw new IndexOutOfRangeException(\"Index cannot be greater than or equal to the count\");\r\n#endif\r\n\r\n        return index;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Clears this <see cref=\"UnsafeList{T}\"/> instance.\r\n    /// </summary>\r\n    /// <exception cref=\"NotImplementedException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        Count = 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Disposes this instance and releases its memory. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        _array.Dispose();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeList{T}\"/> instance into a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>A new instance of <see cref=\"Span{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Span<T> AsSpan()\r\n    {\r\n        return new Span<T>(_array, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"UnsafeEnumerator{T}\"/> for ref acessing the list content.\r\n    /// </summary>\r\n    /// <returns>A new <see cref=\"UnsafeEnumerator{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public UnsafeEnumerator<T> GetEnumerator()\r\n    {\r\n        return new UnsafeEnumerator<T>(_array, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerable{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    IEnumerator<T> IEnumerable<T>.GetEnumerator()\r\n    {\r\n        return new UnsafeIEnumerator<T>(_array, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerator\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    IEnumerator IEnumerable.GetEnumerator()\r\n    {\r\n        return new UnsafeIEnumerator<T>(_array, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"other\">The other <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    public bool Equals(UnsafeList<T> other)\r\n    {\r\n        return _array.Equals(other._array) && Count == other.Count && Capacity == other.Capacity;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"obj\">The other <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    public override bool Equals(object? obj)\r\n    {\r\n        return obj is UnsafeList<T> other && Equals(other);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for equality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    public static bool operator ==(UnsafeList<T> left, UnsafeList<T> right)\r\n    {\r\n        return left.Equals(right);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks for inequality.\r\n    /// </summary>\r\n    /// <param name=\"left\">The first <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <param name=\"right\">The second <see cref=\"UnsafeList{T}\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    public static bool operator !=(UnsafeList<T> left, UnsafeList<T> right)\r\n    {\r\n        return !left.Equals(right);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the hashcode of this <see cref=\"UnsafeList{T}\"/>.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public override int GetHashCode()\r\n    {\r\n        unchecked\r\n        {\r\n            var hashCode = _array.GetHashCode();\r\n            hashCode = (hashCode * 397) ^ Count;\r\n            hashCode = (hashCode * 397) ^ Capacity;\r\n            return hashCode;\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeList{T}\"/> to a string.\r\n    /// </summary>\r\n    /// <returns>The string.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public override string ToString()\r\n    {\r\n        var items = new StringBuilder();\r\n        foreach (ref var item in this)\r\n        {\r\n            items.Append($\"{item},\");\r\n        }\r\n        items.Length--;\r\n        return $\"UnsafeList<{typeof(T).Name}>[{Count}]{{{items}}}\";\r\n    }\r\n}\r\n\r\n\r\n/// <summary>\r\n///     A debug view for the <see cref=\"UnsafeList{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged type.</typeparam>\r\ninternal class UnsafeListDebugView<T> where T : unmanaged\r\n{\r\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\r\n    private readonly UnsafeList<T> _entity;\r\n\r\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\r\n    public T[] Items\r\n    {\r\n        get\r\n        {\r\n            var items = new T[_entity.Count];\r\n            _entity.CopyTo(items, 0);\r\n            return items;\r\n        }\r\n    }\r\n\r\n    public UnsafeListDebugView(UnsafeList<T> entity) => _entity = entity;\r\n}"
  },
  {
    "path": "Arch.LowLevel/UnsafeQueue.cs",
    "content": "﻿using System.Collections;\r\nusing System.Diagnostics;\r\nusing System.Diagnostics.Contracts;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Text;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The struct <see cref=\"UnsafeStack{T}\"/> represents a native unmanaged queue.\r\n///     Can easily be stored in unmanaged structs. \r\n/// </summary>\r\n/// <typeparam name=\"T\">The generic type stored in the queue.</typeparam>\r\n[DebuggerTypeProxy(typeof(UnsafeQueueDebugView<>))]\r\npublic unsafe struct UnsafeQueue<T> : IEnumerable<T>, IDisposable where T : unmanaged\r\n{\r\n    private UnsafeArray<T> _queue;\r\n    private int _capacity;\r\n    private int _frontIndex;\r\n    private int _count;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeQueue{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">Initial capacity of this queue.</param>\r\n    /// <exception cref=\"ArgumentOutOfRangeException\"></exception>\r\n    public UnsafeQueue(int capacity)\r\n    {\r\n        if (capacity <= 0)\r\n        {\r\n            throw new ArgumentOutOfRangeException(nameof(capacity), \"Capacity must be greater than 0.\");\r\n        }\r\n        \r\n        _queue = new UnsafeArray<T>(capacity);\r\n        _capacity = capacity;\r\n        _frontIndex =  _count = 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     The amount of items in the queue.\r\n    /// </summary>\r\n    public int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The total capacity of this queue.\r\n    /// </summary>\r\n    public int Capacity\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _capacity;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Enqueues a item.\r\n    /// </summary>\r\n    /// <param name=\"item\">The item</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Enqueue(T item)\r\n    {\r\n        if (Count == Capacity)\r\n        {\r\n            EnsureCapacity(_capacity * 2);\r\n        }\r\n\r\n        var itemOffset = (_frontIndex + _count) % _capacity;\r\n        _queue[itemOffset] = item;\r\n        _count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Dequeues an item.\r\n    /// </summary>\r\n    /// <returns>The item</returns>\r\n    /// <exception cref=\"InvalidOperationException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public T Dequeue()\r\n    {\r\n        if (_count == 0)\r\n        {\r\n            throw new InvalidOperationException(\"Queue is empty\");\r\n        }\r\n\r\n        var item = Peek();\r\n        _frontIndex = (_frontIndex + 1) % _capacity;\r\n        _count--;\r\n        return item;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Peeks at an item.\r\n    /// </summary>\r\n    /// <returns>The item.</returns>\r\n    /// <exception cref=\"InvalidOperationException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T Peek()\r\n    {\r\n        if (_count == 0)\r\n        {\r\n            throw new InvalidOperationException(\"Queue is empty\");\r\n        }\r\n\r\n        return ref _queue[_frontIndex];\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Trims this instance and releases memory in this process.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        var newCapacity = _count;\r\n        SetCapacity(newCapacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity of this instance. \r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capacity.</param>\r\n    /// <exception cref=\"ArgumentException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity <= _capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        SetCapacity(newCapacity);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the capacity of this instance. \r\n    /// </summary>\r\n    /// <param name=\"newCapacity\">The new capacity.</param>\r\n    /// <exception cref=\"ArgumentException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    private void SetCapacity(int newCapacity)\r\n    {\r\n        if (newCapacity < _count)\r\n        {\r\n            throw new ArgumentOutOfRangeException(nameof(newCapacity), \"newCapacity cannot be smaller than _count\");\r\n        }\r\n\r\n        var newBuffer = new UnsafeArray<T>(newCapacity);\r\n        if (_count > 0)\r\n        {\r\n            var firstChunkCount = Math.Min(_count, _capacity - _frontIndex);\r\n            var secondChunkCount = _count - firstChunkCount;\r\n\r\n            // Copy elements in front->rear order to the new buffer\r\n            if (firstChunkCount > 0)\r\n            {\r\n                UnsafeArray.Copy(ref _queue, _frontIndex, ref newBuffer, 0, firstChunkCount);\r\n            }\r\n\r\n            if (secondChunkCount > 0)\r\n            {\r\n                UnsafeArray.Copy(ref _queue, 0, ref newBuffer, firstChunkCount, secondChunkCount);\r\n            }\r\n        }\r\n        \r\n        _queue.Dispose();\r\n        \r\n        _queue = newBuffer;\r\n        _capacity = newCapacity;\r\n        _frontIndex = 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Clears this instance.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        _frontIndex = _count = 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Disposes this instance. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        _queue.Dispose();\r\n        _capacity = _frontIndex  = _count = 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeQueue{T}\"/> instance into a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>A new instance of <see cref=\"Span{T}\"/>.</returns>\r\n    [Pure]\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public Span<T> AsSpan()\r\n    {\r\n        return new Span<T>(_queue, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"UnsafeEnumerator{T}\"/> for ref acessing the list content.\r\n    /// </summary>\r\n    /// <returns>A new <see cref=\"UnsafeEnumerator{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public UnsafeEnumerator<T> GetEnumerator()\r\n    {\r\n        return new UnsafeEnumerator<T>(_queue, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerable{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    IEnumerator<T> IEnumerable<T>.GetEnumerator()\r\n    {\r\n        return new UnsafeIEnumerator<T>(_queue, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerator\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    IEnumerator IEnumerable.GetEnumerator()\r\n    {\r\n        return new UnsafeIEnumerator<T>(_queue, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeStack{T}\"/> to a string.\r\n    /// </summary>\r\n    /// <returns>The string.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public override string ToString()\r\n    {\r\n        var items = new StringBuilder();\r\n        foreach (ref var item in this)\r\n        {\r\n            items.Append($\"{item},\");\r\n        }\r\n        items.Length--;\r\n        return $\"UnsafeQueue<{typeof(T).Name}>[{Count}]{{{items}}}\";\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     A debug view for the <see cref=\"UnsafeQueue{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged type.</typeparam>\r\ninternal class UnsafeQueueDebugView<T> where T : unmanaged\r\n{\r\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\r\n    private readonly UnsafeQueue<T> _entity;\r\n\r\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\r\n    public T[] Items\r\n    {\r\n        get\r\n        {\r\n            var items = new T[_entity.Count];\r\n            _entity.AsSpan().CopyTo(items);\r\n            return items;\r\n        }\r\n    }\r\n\r\n    public UnsafeQueueDebugView(UnsafeQueue<T> entity) => _entity = entity;\r\n}"
  },
  {
    "path": "Arch.LowLevel/UnsafeStack.cs",
    "content": "﻿using System.Collections;\r\nusing System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Text;\r\n\r\nnamespace Arch.LowLevel;\r\n\r\n/// <summary>\r\n///     The struct <see cref=\"UnsafeStack{T}\"/> represents a native unmanaged stack.\r\n///     Can easily be stored in unmanaged structs. \r\n/// </summary>\r\n/// <typeparam name=\"T\">The generic type stored in the stack.</typeparam>\r\n[DebuggerTypeProxy(typeof(UnsafeStackDebugView<>))]\r\npublic unsafe struct UnsafeStack<T> :  IEnumerable<T>, IDisposable where T : unmanaged  \r\n{\r\n    private const int DefaultCapacity = 4;\r\n    \r\n    /// <summary>\r\n    ///     The stack pointer.\r\n    /// </summary>\r\n    private UnsafeArray<T> _stack;\r\n    \r\n    /// <summary>\r\n    ///     Its capacity.\r\n    /// </summary>\r\n    private int _capacity;\r\n    \r\n    /// <summary>\r\n    ///     Its count.\r\n    /// </summary>\r\n    private int _count;\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of the <see cref=\"UnsafeStack{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"capacity\">The initial capacity that is being allocated.</param>\r\n    public UnsafeStack(int capacity = DefaultCapacity)\r\n    {\r\n        if (capacity <= 0)\r\n        {\r\n            throw new ArgumentOutOfRangeException(nameof(capacity), \"Capacity must be greater than 0.\");\r\n        }\r\n\r\n        _stack = new UnsafeArray<T>(capacity);\r\n        _capacity = capacity;\r\n        _count = 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The amount of items in the stack.\r\n    /// </summary>\r\n    public readonly int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The total capacity of this stack.\r\n    /// </summary>\r\n    public readonly int Capacity\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _capacity;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this stack is empty.\r\n    /// </summary>\r\n    public readonly bool IsEmpty\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _count == 0;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     If this stack is full. \r\n    /// </summary>\r\n    public readonly bool IsFull\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => _count >= _capacity;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Pushes an item to the <see cref=\"UnsafeStack{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"value\">The item.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Push(T value)\r\n    {\r\n        if (Count == Capacity)\r\n        {\r\n            EnsureCapacity(_capacity * 2);\r\n        }\r\n        \r\n        _stack[_count] = value;\r\n        _count++;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Pops the first item of this <see cref=\"UnsafeStack{T}\"/> and returns it.\r\n    /// </summary>\r\n    /// <returns>The item.</returns>\r\n    /// <exception cref=\"InvalidOperationException\">If the stack is empty.</exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public T Pop()\r\n    {\r\n        if (_count == 0)\r\n        {\r\n            throw new InvalidOperationException(\"Stack is empty.\");\r\n        }\r\n\r\n        _count--;\r\n        return _stack[_count];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Peeks at the first item of this <see cref=\"UnsafeStack{T}\"/> and returns it. \r\n    /// </summary>\r\n    /// <returns>The item.</returns>\r\n    /// <exception cref=\"InvalidOperationException\">If the stack is empty.</exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public ref T Peek()\r\n    {\r\n        if (_count == 0)\r\n        {\r\n            throw new InvalidOperationException(\"Stack is empty.\");\r\n        }\r\n\r\n        return ref _stack[_count - 1];\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Ensures the capacity of this <see cref=\"UnsafeStack{T}\"/> instance and resizes it accordingly.\r\n    /// </summary>\r\n    /// <param name=\"min\">The minimum amount of items ensured.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void EnsureCapacity(int min)\r\n    {\r\n        if (min <= _capacity)\r\n        {\r\n            return;\r\n        }\r\n\r\n        var newCapacity = _capacity * 2;\r\n        if (newCapacity < min)\r\n        {\r\n            newCapacity = min;\r\n        }\r\n\r\n        // Create new stack and copy elements\r\n        var newStack = new UnsafeArray<T>(newCapacity);\r\n        UnsafeArray.Copy(ref _stack, 0, ref newStack,0, _count);\r\n        _stack.Dispose();\r\n\r\n        _capacity = newCapacity;\r\n        _stack = newStack;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Trims the capacity of this <see cref=\"UnsafeStack{T}\"/> to release unused memory.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void TrimExcess()\r\n    {\r\n        var newCapacity = _count == 0 ? DefaultCapacity : _count;\r\n        if (newCapacity >= _capacity)\r\n        {\r\n            return;\r\n        }\r\n        \r\n        // Create new stack and copy elements\r\n        var newStack = new UnsafeArray<T>(newCapacity);\r\n        UnsafeArray.Copy(ref _stack, 0, ref newStack,0, _count);\r\n        _stack.Dispose();\r\n        \r\n        _capacity = newCapacity;\r\n        _stack = newStack;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Clears this <see cref=\"UnsafeList{T}\"/> instance.\r\n    /// </summary>\r\n    /// <exception cref=\"NotImplementedException\"></exception>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Clear()\r\n    {\r\n        _count = 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Disposes this instance and releases its memory. \r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Dispose()\r\n    {\r\n        _stack.Dispose();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeStack{T}\"/> instance into a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>A new instance of <see cref=\"Span{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public readonly Span<T> AsSpan()\r\n    {\r\n        return new Span<T>(_stack, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"UnsafeEnumerator{T}\"/> for ref acessing the list content.\r\n    /// </summary>\r\n    /// <returns>A new <see cref=\"UnsafeEnumerator{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public readonly UnsafeReverseEnumerator<T> GetEnumerator()\r\n    {\r\n        return new UnsafeReverseEnumerator<T>(_stack, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerable{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    readonly IEnumerator<T> IEnumerable<T>.GetEnumerator()\r\n    {\r\n        return new ReverseIEnumerator<T>(_stack, Count);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance of a <see cref=\"IEnumerable{T}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"IEnumerator\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    readonly IEnumerator IEnumerable.GetEnumerator()\r\n    {\r\n        return new ReverseIEnumerator<T>(_stack, Count);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Converts this <see cref=\"UnsafeStack{T}\"/> to a string.\r\n    /// </summary>\r\n    /// <returns>The string.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public readonly override string ToString()\r\n    {\r\n        var items = new StringBuilder();\r\n        foreach (ref var item in this)\r\n        {\r\n            items.Append($\"{item},\");\r\n        }\r\n        items.Length--;\r\n        return $\"UnsafeStack<{typeof(T).Name}>[{Count}]{{{items}}}\";\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     A debug view for the <see cref=\"UnsafeQueue{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The unmanaged type.</typeparam>\r\ninternal class UnsafeStackDebugView<T> where T : unmanaged\r\n{\r\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\r\n    private readonly UnsafeStack<T> _entity;\r\n\r\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\r\n    public T[] Items\r\n    {\r\n        get\r\n        {\r\n            var items = new T[_entity.Count];\r\n            _entity.AsSpan().CopyTo(items);\r\n            return items;\r\n        }\r\n    }\r\n\r\n    public UnsafeStackDebugView(UnsafeStack<T> entity) => _entity = entity;\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/Arch.LowLevel.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFramework>net7.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n\r\n        <IsPackable>false</IsPackable>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.2.0\" />\r\n        <PackageReference Include=\"NUnit\" Version=\"3.13.3\" />\r\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.2.1\" />\r\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"3.3.0\" />\r\n        <PackageReference Include=\"coverlet.collector\" Version=\"3.1.2\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n      <ProjectReference Include=\"..\\Arch.LowLevel\\Arch.LowLevel.csproj\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.LowLevel.Tests/ArrayTest.cs",
    "content": "﻿using System.ComponentModel.DataAnnotations;\r\n\r\nnamespace Arch.LowLevel.Tests;\r\nusing static Assert;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"Array{T}\"/> related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class ArrayTest\r\n{\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Array{T}\"/> is capable of allocating space and adding items.\r\n    /// </summary>\r\n    [Test]\r\n    public void ArrayCreate()\r\n    {\r\n        var array = new Array<int>(3);\r\n        array[0] = 1;\r\n        array[1] = 2;\r\n        array[2] = 3;\r\n        \r\n        That(array.Count, Is.EqualTo(3));\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayEnumerator()\r\n    {\r\n        var array = new Array<int>(3);\r\n        array[0] = 1;\r\n        array[1] = 2;\r\n        array[2] = 3;\r\n\r\n        var count = 1;\r\n        foreach (var item in array)\r\n            That(item, Is.EqualTo(count++));\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayEmptyIsEmpty()\r\n    {\r\n        var empty = Array.Empty<long>();\r\n        That(empty, Is.Empty);\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayFill()\r\n    {\r\n        var array = new Array<int>(35);\r\n        Array.Fill(ref array, 8);\r\n\r\n        for (var i = 0; i < array.Length; i++)\r\n            That(array[i], Is.EqualTo(8));\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayCopy()\r\n    {\r\n        var src = new Array<int>(15);\r\n        var dst = new Array<int>(6);\r\n\r\n        for (var i = 0; i < src.Length; i++)\r\n            src[i] = i;\r\n\r\n        Array.Fill(ref dst);\r\n        Array.Copy(ref src, 4, ref dst, 1, 4);\r\n\r\n        Multiple(() =>\r\n        {\r\n            That(dst[0], Is.EqualTo(0));\r\n            That(dst[1], Is.EqualTo(4));\r\n            That(dst[2], Is.EqualTo(5));\r\n            That(dst[3], Is.EqualTo(6));\r\n            That(dst[4], Is.EqualTo(7));\r\n            That(dst[5], Is.EqualTo(0));\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayResizeShrink()\r\n    {\r\n        var array = new Array<int>(19);\r\n        for (var i = 0; i < array.Length; i++)\r\n            array[i] = i;\r\n\r\n        var resized = Array.Resize(ref array, 8);\r\n        for (var i = 0; i < resized.Length; i++)\r\n            That(resized[i], Is.EqualTo(i));\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayResizeGrow()\r\n    {\r\n        var array = new Array<int>(8);\r\n        for (var i = 0; i < array.Length; i++)\r\n            array[i] = i;\r\n\r\n        var resized = Array.Resize(ref array, 19);\r\n        for (var i = 0; i < array.Length; i++)\r\n            That(resized[i], Is.EqualTo(i));\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayEquals()\r\n    {\r\n        var a = new Array<int>(8);\r\n        var b = a;\r\n\r\n        That(a, Is.EqualTo(b));\r\n        That(a == b, Is.True);\r\n    }\r\n\r\n    [Test]\r\n    public void ArrayNotEquals()\r\n    {\r\n        var a = new Array<int>(8);\r\n        var b = new Array<int>(8);\r\n\r\n        That(a, Is.Not.EqualTo(b));\r\n        That(a != b, Is.True);\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/Jagged/JaggedArrayTest.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing Arch.LowLevel.Jagged;\r\n\r\nnamespace Arch.LowLevel.Tests.Jagged;\r\nusing static Assert;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"JaggedArray{T}\"/>  related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class JaggedArrayTest\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"JaggedArray{T}\"/> is capable of adding items correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void Add([Values(256,512,1024,2048,4096)] int capacity)\r\n    {\r\n        // Check add\r\n        var jaggedArray = new JaggedArray<int>(16000/Unsafe.SizeOf<int>(), -1, capacity);\r\n        \r\n        // adding\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            jaggedArray.Add(index, index);\r\n        }\r\n \r\n        // Checking\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            var item = jaggedArray[index];\r\n            That(item, Is.EqualTo(index));\r\n        }\r\n        \r\n        That(jaggedArray.Capacity, Is.GreaterThan(capacity));\r\n    }\r\n    \r\n    [Test]\r\n    public void TryGetValue([Values(256,512,1024,2048,4096)] int capacity)\r\n    {\r\n        // Initialize the JaggedArray\r\n        var jaggedArray = new JaggedArray<int>(16000/Unsafe.SizeOf<int>(), -1, capacity);\r\n    \r\n        // Add elements to the array\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            jaggedArray.Add(index, index);\r\n        }\r\n\r\n        // Check values using TryGetValue\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            var found = jaggedArray.TryGetValue(index, out int value);\r\n            That(found, Is.True);\r\n            That(value, Is.EqualTo(index));\r\n        }\r\n\r\n        // Check for values out of bounds\r\n        var outOfBoundsFound = jaggedArray.TryGetValue(jaggedArray.Capacity, out int _);\r\n        That(outOfBoundsFound, Is.False);\r\n    }\r\n    \r\n    [Test]\r\n    public void TryGetValueRef([Values(256,512,1024,2048,4096)] int capacity)\r\n    {\r\n        // Initialize the JaggedArray\r\n        var jaggedArray = new JaggedArray<int>(16000/Unsafe.SizeOf<int>(), -1, capacity);\r\n    \r\n        // Add elements to the array\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            jaggedArray.Add(index, index);\r\n        }\r\n\r\n        // Check values using TryGetValue\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            bool found;\r\n            ref var value = ref jaggedArray.TryGetValue(index, out found);\r\n            That(found, Is.True);\r\n            That(value, Is.EqualTo(index));\r\n        }\r\n\r\n        // Check for values out of bounds\r\n        ref var outOfBoundsValue = ref jaggedArray.TryGetValue(jaggedArray.Capacity, out bool outOfBoundsFound);\r\n        That(outOfBoundsFound, Is.False);\r\n    }\r\n\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"JaggedArray{T}\"/> is capable of adding items correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void Remove([Values(256,512,1024,2048,4096)] int capacity)\r\n    {\r\n        // Check add\r\n        var jaggedArray = new JaggedArray<int>(16000/Unsafe.SizeOf<int>(), -1, capacity);\r\n        \r\n        // Adding\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            jaggedArray.Add(index, index);\r\n        }\r\n \r\n        // Removing\r\n        for (var index = jaggedArray.Capacity-1; index >= 0; index--)\r\n        {\r\n            jaggedArray.Remove(index);\r\n        }\r\n        \r\n        // Checking\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            var item = jaggedArray[index];\r\n            That(item, Is.EqualTo(-1));\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"JaggedArray{T}\"/> is capable of adding items correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void TrimExcess([Values(2560,5120,10240)] int capacity)\r\n    {\r\n        // Check add\r\n        var jaggedArray = new JaggedArray<int>(16000/Unsafe.SizeOf<int>(), -1, capacity);\r\n        \r\n        // Adding\r\n        for (var index = 0; index < jaggedArray.Capacity; index++)\r\n        {\r\n            jaggedArray.Add(index, index);\r\n        }\r\n \r\n        // Removing half of items\r\n        for (var index = jaggedArray.Capacity-1; index >= jaggedArray.Capacity/2; index--)\r\n        {\r\n            jaggedArray.Remove(index);\r\n        }\r\n\r\n        var buckets = jaggedArray.Buckets;\r\n        jaggedArray.TrimExcess();\r\n        That(jaggedArray.Buckets, Is.EqualTo((buckets + 2 - 1)/2));\r\n        \r\n        // Checking first half still having the desired value\r\n        for (var index = 0; index < jaggedArray.Capacity/2; index++)\r\n        {\r\n            var item = jaggedArray[index];\r\n            That(item, Is.EqualTo(index));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/ResourcesTest.cs",
    "content": "using static NUnit.Framework.Assert;\r\n\r\nnamespace Arch.LowLevel.Tests;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"Resources{T}\"/> and HashCode related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class ResourcesTest\r\n{\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of adding <see cref=\"Handle{T}\"/>s.\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesAddHandle()\r\n    {\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n        var nextHandle = resources.Add(\"NextHandle\");\r\n\r\n        That(handle.Id, Is.EqualTo(0));\r\n        That(nextHandle.Id, Is.EqualTo(1));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of adding many more <see cref=\"Handle{T}\"/>s than the capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesAddManyHandles()\r\n    {\r\n        const int count = 10000;\r\n\r\n        using var resources = new Resources<string>(capacity: 3);\r\n\r\n        var handles = new List<Handle<string>>();\r\n        for (var i = 0; i < count; i++)\r\n            handles.Add(resources.Add(i.ToString()));\r\n\r\n        resources.TrimExcess();\r\n\r\n        That(resources.Count, Is.EqualTo(count));\r\n\r\n        for (var i = 0; i < handles.Count; i++)\r\n            That(resources.Get(handles[i]), Is.EqualTo(i.ToString()));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of getting <see cref=\"Handle{T}\"/>s.\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesGetHandle()\r\n    {\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n        var nextHandle = resources.Add(\"NextHandle\");\r\n\r\n        // Check get\r\n        var handleString = resources.Get(in handle);\r\n        var nextHandleString = resources.Get(in nextHandle);\r\n\r\n        That(handleString, Is.EqualTo(\"Handle\"));\r\n        That(nextHandleString, Is.EqualTo(\"NextHandle\"));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of removing <see cref=\"Handle{T}\"/>s.\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesRemoveHandle()\r\n    {\r\n\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n        var nextHandle = resources.Add(\"NextHandle\");\r\n\r\n        // Check remove\r\n        resources.Remove(in handle);\r\n        resources.Remove(in nextHandle);\r\n\r\n        That(resources._ids.Count, Is.EqualTo(2));\r\n        That(resources.Count, Is.EqualTo(0));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of removing <see cref=\"Handle{T}\"/>s.\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesRecycleHandle()\r\n    {\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n        var nextHandle = resources.Add(\"NextHandle\");\r\n\r\n        // Check remove\r\n        resources.Remove(in handle);\r\n        resources.Remove(in nextHandle);\r\n\r\n        var newHandle = resources.Add(\"NewString\");\r\n        That(newHandle.Id, Is.EqualTo(0));\r\n        That(resources.Count, Is.EqualTo(1));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> is capable of validating a <see cref=\"Handle{T}\"/>.\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesHandleValid()\r\n    {\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n        Handle<string> someHandle = Handle<string>.NULL;\r\n        \r\n        That(resources.IsValid(handle), Is.EqualTo(true));\r\n        That(resources.IsValid(someHandle), Is.EqualTo(false));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"Resources{T}\"/> throws after Dispose\r\n    /// </summary>\r\n    [Test]\r\n    public void ResourcesDispose()\r\n    {\r\n        // Check add\r\n        var resources = new Resources<string>(IntPtr.Size, capacity: 64);\r\n        var handle = resources.Add(\"Handle\");\r\n\r\n        // Check get\r\n        That(resources.Get(in handle), Is.EqualTo(\"Handle\"));\r\n        \r\n        resources.Dispose();\r\n\r\n        That(resources.Count, Is.EqualTo(0));\r\n\r\n        // Check that get fails\r\n        Throws<NullReferenceException>(() =>\r\n        {\r\n            resources.Get(in handle);\r\n        });\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/UnsafeArrayTest.cs",
    "content": "﻿using System.ComponentModel.DataAnnotations;\r\n\r\nnamespace Arch.LowLevel.Tests;\r\nusing static Assert;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"UnsafeArray{T}\"/> related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class UnsafeArrayTest\r\n{\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeArray{T}\"/> is capable of allocating space and adding items.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeArrayCreate()\r\n    {\r\n        using var array = new UnsafeArray<int>(3);\r\n        array[0] = 1;\r\n        array[1] = 2;\r\n        array[2] = 3;\r\n        \r\n        That(array.Count, Is.EqualTo(3));\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayEnumerator()\r\n    {\r\n        using var array = new UnsafeArray<int>(3);\r\n        array[0] = 1;\r\n        array[1] = 2;\r\n        array[2] = 3;\r\n\r\n        var count = 1;\r\n        foreach (var item in array)\r\n            That(item, Is.EqualTo(count++));\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayEmptyIsEmpty()\r\n    {\r\n        var empty = UnsafeArray.Empty<long>();\r\n\r\n        That(empty, Is.Empty);\r\n\r\n        empty.Dispose();\r\n\r\n        That(empty, Is.Empty);\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayFill()\r\n    {\r\n        var array = new UnsafeArray<int>(35);\r\n        using (array)\r\n        {\r\n#pragma warning disable CS0728 // Possibly incorrect assignment to local which is the argument to a using or lock statement\r\n            UnsafeArray.Fill(ref array, 8);\r\n#pragma warning restore CS0728 // Possibly incorrect assignment to local which is the argument to a using or lock statement\r\n\r\n            for (var i = 0; i < array.Length; i++)\r\n                That(array[i], Is.EqualTo(8));\r\n        }\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayCopy()\r\n    {\r\n        var src = new UnsafeArray<int>(15);\r\n        var dst = new UnsafeArray<int>(6);\r\n        using (src)\r\n        using (dst)\r\n        {\r\n            for (var i = 0; i < src.Length; i++)\r\n                src[i] = i;\r\n\r\n#pragma warning disable CS0728 // Possibly incorrect assignment to local which is the argument to a using or lock statement\r\n            UnsafeArray.Fill(ref dst);\r\n            UnsafeArray.Copy(ref src, 4, ref dst, 1, 4);\r\n#pragma warning restore CS0728 // Possibly incorrect assignment to local which is the argument to a using or lock statement\r\n\r\n            Multiple(() =>\r\n            {\r\n                That(dst[0], Is.EqualTo(0));\r\n                That(dst[1], Is.EqualTo(4));\r\n                That(dst[2], Is.EqualTo(5));\r\n                That(dst[3], Is.EqualTo(6));\r\n                That(dst[4], Is.EqualTo(7));\r\n                That(dst[5], Is.EqualTo(0));\r\n            });\r\n        }\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayResizeShrink()\r\n    {\r\n        var array = new UnsafeArray<int>(19);\r\n        for (var i = 0; i < array.Length; i++)\r\n            array[i] = i;\r\n\r\n        var resized = UnsafeArray.Resize(ref array, 8);\r\n        for (var i = 0; i < resized.Length; i++)\r\n            That(resized[i], Is.EqualTo(i));\r\n\r\n        resized.Dispose();\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayResizeGrow()\r\n    {\r\n        var array = new UnsafeArray<int>(8);\r\n        for (var i = 0; i < array.Length; i++)\r\n            array[i] = i;\r\n\r\n        var resized = UnsafeArray.Resize(ref array, 19);\r\n        for (var i = 0; i < array.Length; i++)\r\n            That(resized[i], Is.EqualTo(i));\r\n\r\n        resized.Dispose();\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayEquals()\r\n    {\r\n        using var a = new UnsafeArray<int>(8);\r\n        var b = a;\r\n\r\n        That(a, Is.EqualTo(b));\r\n        That(a == b, Is.True);\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeArrayNotEquals()\r\n    {\r\n        using var a = new UnsafeArray<int>(8);\r\n        using var b = new UnsafeArray<int>(8);\r\n\r\n        That(a, Is.Not.EqualTo(b));\r\n        That(a != b, Is.True);\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/UnsafeListTest.cs",
    "content": "﻿using System.Collections;\r\nusing static NUnit.Framework.Assert;\r\nnamespace Arch.LowLevel.Tests;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"UnsafeList{T}\"/> related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class UnsafeListTest\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of adding items.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListAdd()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        That(list.IsReadOnly, Is.False);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n        \r\n        That(list.Count, Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> GetHashCode is different for different lists\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListGetHashCode()\r\n    {\r\n        using var list1 = new UnsafeList<int>(8);\r\n        using var list2 = new UnsafeList<int>(8);\r\n\r\n        That(list1.GetHashCode(), Is.Not.EqualTo(list2.GetHashCode()));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> can access items by index\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListRefIndex()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(7);\r\n\r\n        ref var item0 = ref list[0];\r\n        That(item0, Is.EqualTo(7));\r\n        item0 = 11;\r\n        That(list[0], Is.EqualTo(11));\r\n\r\n#if DEBUG\r\n        Throws<IndexOutOfRangeException>(() => { var x = list[-1]; });\r\n        Throws<IndexOutOfRangeException>(() => { var x = list[2]; });\r\n#endif\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> can access items by index\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListIndex()\r\n    {\r\n        using var unsafelist = new UnsafeList<int>(8);\r\n        unsafelist.Add(7);\r\n\r\n        var list = (IList<int>)unsafelist;\r\n\r\n        That(list[0], Is.EqualTo(7));\r\n        list[0] = 11;\r\n        That(list[0], Is.EqualTo(11));\r\n\r\n#if DEBUG\r\n        Throws<IndexOutOfRangeException>(() => { var x = list[-1]; });\r\n        Throws<IndexOutOfRangeException>(() => { var x = list[2]; });\r\n#endif\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of being copied to an array.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListCopyTo()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        var arr = new int[10];\r\n\r\n        // Basic copy into the array\r\n        list.CopyTo(arr, 3);\r\n        CollectionAssert.AreEqual(new[] { 0, 0, 0, 1, 2, 3, 0, 0, 0, 0 }, arr);\r\n\r\n        // Copy into a bad index\r\n        Throws<IndexOutOfRangeException>(() => { list.CopyTo(arr, -3); });\r\n        Throws<IndexOutOfRangeException>(() => { list.CopyTo(arr, arr.Length + 1); });\r\n\r\n        // Copy into an index near the end, so there's not enough space\r\n        Throws<ArgumentException>(() => list.CopyTo(arr, 8));\r\n\r\n        // Check that copying into an array from an empty list does nothing\r\n        list.Clear();\r\n        var arr2 = arr.ToArray();\r\n        list.CopyTo(arr, 0);\r\n        CollectionAssert.AreEqual(arr, arr2);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of being cleared.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListClear()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        list.Clear();\r\n        That(list, Is.Empty);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is can be converted into a span.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListAsSpan()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, list.AsSpan().ToArray());\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> equality works as expected\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListEquality()\r\n    {\r\n        using var list1 = new UnsafeList<int>(8);\r\n        list1.Add(1);\r\n        list1.Add(2);\r\n        list1.Add(3);\r\n\r\n        using var list2 = new UnsafeList<int>(8);\r\n        list2.Add(1);\r\n        list2.Add(2);\r\n        list2.Add(3);\r\n\r\n        That(list1 == list2, Is.False);\r\n        That(list1 != list2, Is.True);\r\n\r\n        var list1a = list1;\r\n        That(list1 == list1a, Is.True);\r\n        That(list1 != list1a, Is.False);\r\n\r\n        That(list1.Equals((object)list2), Is.False);\r\n        That(list1.Equals((object)list1), Is.True);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of adding items at a given index.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListInsertAt()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(3);\r\n        list.Insert(1,2);\r\n        \r\n        That(list.Count, Is.EqualTo(3));\r\n        That(list[0], Is.EqualTo(1));\r\n        That(list[1], Is.EqualTo(2));\r\n        That(list[2], Is.EqualTo(3));\r\n\r\n        // Check that adding past the end throws\r\n        Assert.Throws<ArgumentOutOfRangeException>(() =>\r\n        {\r\n            list.Insert(5, 5);\r\n        });\r\n\r\n        // Add lots of items, to force capacity to grow\r\n        var count = 10;\r\n        for (var i = 0; i < count; i++)\r\n            list.Insert(0, 0);\r\n\r\n        CollectionAssert.AreEqual(new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 }, list);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of removing itemss.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListRemoveAt()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n        \r\n        list.RemoveAt(0);\r\n        list.RemoveAt(2);\r\n        \r\n        That(list.Count, Is.EqualTo(1));\r\n        That(list[0], Is.EqualTo(2));\r\n\r\n        Throws<ArgumentOutOfRangeException>(() =>\r\n        {\r\n            list.RemoveAt(-1);\r\n        });\r\n        Throws<ArgumentOutOfRangeException>(() =>\r\n        {\r\n            list.RemoveAt(10);\r\n        });\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of removing items by value.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListRemove()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        That(list.Remove(2), Is.True);\r\n        That(list.Remove(4), Is.False);\r\n\r\n        That(list.Count, Is.EqualTo(2));\r\n        That(list[1], Is.EqualTo(3));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of checking for a contained value.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListContains()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n        \r\n        That(list.Count, Is.EqualTo(3));\r\n        That(list.Contains(2), Is.EqualTo(true));\r\n        That(list.Contains(0), Is.EqualTo(false));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of checking for a contained value.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListIndexOf()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n        \r\n        That(list.Count, Is.EqualTo(3));\r\n        That(list.IndexOf(2), Is.EqualTo(1));\r\n        That(list.IndexOf(0), Is.EqualTo(-1));\r\n        That(list.IndexOf(4), Is.EqualTo(-1));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of ensuring capacity.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListEnsureCapacity()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.EnsureCapacity(16);\r\n        list.Add(0);\r\n        list.Add(1);\r\n        \r\n        That(list.Capacity, Is.EqualTo(16));\r\n        That(list.IndexOf(0), Is.EqualTo(0));\r\n        That(list.IndexOf(1), Is.EqualTo(1));\r\n\r\n        // This should do nothing\r\n        list.EnsureCapacity(list.Count);\r\n        That(list.Capacity, Is.EqualTo(16));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of trimming capacity.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListTrimExcess()\r\n    {\r\n        using var list = new UnsafeList<int>(16);\r\n        list.Add(0);\r\n        list.Add(1);\r\n        list.TrimExcess();\r\n        \r\n        That(list.Capacity, Is.EqualTo(2));\r\n        That(list.IndexOf(0), Is.EqualTo(0));\r\n        That(list.IndexOf(1), Is.EqualTo(1));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of iterating with its enumerators.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListEnumerator()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        // Ref iterator\r\n        var count = 0;\r\n        foreach (ref var item in list)\r\n        {\r\n            That(++count, Is.EqualTo(item));\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n        \r\n        // Ilist iterator\r\n        count = 0;\r\n        foreach (var item in list as IList<int>)\r\n        {\r\n            That(++count, Is.EqualTo(item));\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n\r\n        // non-generic enumerator\r\n        count = 0;\r\n        foreach (var item in ((IEnumerable)list))\r\n        {\r\n            That(++count, Is.EqualTo(item));\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the unsafe list enumerator can be reset\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListAsIListEnumeratorReset()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        using var enumerator = ((IList<int>)list).GetEnumerator();\r\n\r\n        That(enumerator.MoveNext(), Is.True);\r\n        That(enumerator.Current, Is.EqualTo(1));\r\n        That(enumerator.MoveNext(), Is.True);\r\n        That(enumerator.Current, Is.EqualTo(2));\r\n\r\n        enumerator.Reset();\r\n\r\n        var count = 1;\r\n        foreach (var item in list)\r\n        {\r\n            That(count, Is.EqualTo(item));\r\n            count++;\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the unsafe list enumerator can be reset\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeListEnumeratorReset()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        list.Add(1);\r\n        list.Add(2);\r\n        list.Add(3);\r\n\r\n        var enumerator = list.GetEnumerator();\r\n\r\n        That(enumerator.MoveNext(), Is.True);\r\n        That(enumerator.Current, Is.EqualTo(1));\r\n        That(enumerator.MoveNext(), Is.True);\r\n        That(enumerator.Current, Is.EqualTo(2));\r\n\r\n        enumerator.Reset();\r\n\r\n        var count = 1;\r\n        foreach (var item in list)\r\n        {\r\n            That(count, Is.EqualTo(item));\r\n            count++;\r\n        }\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeListFuzz()\r\n    {\r\n        using var list = new UnsafeList<int>(8);\r\n        var truth = new List<int>();\r\n\r\n        var rng = new Random(3462345);\r\n\r\n        for (var i = 0; i < 1024; i++)\r\n        {\r\n            var index = rng.Next(0, list.Count);\r\n            var value = rng.Next();\r\n            switch (rng.Next(0, 5))\r\n            {\r\n                case 0:\r\n                {\r\n                    truth.Add(value);\r\n                    list.Add(value);\r\n                    break;\r\n                }\r\n\r\n                case 1:\r\n                {\r\n                    truth.Remove(value);\r\n                    list.Remove(value);\r\n                    break;\r\n                }\r\n\r\n                case 2 when list.Count > 0:\r\n                {\r\n                    truth.RemoveAt(index);\r\n                    list.RemoveAt(index);\r\n                    break;\r\n                }\r\n\r\n                case 3:\r\n                {\r\n                    truth.Insert(index, value);\r\n                    list.Insert(index, value);\r\n                    break;\r\n                }\r\n\r\n                case 4 when list.Count > 0:\r\n                {\r\n                    value = truth[index];\r\n                    That(list, Does.Contain(value));\r\n                    break;\r\n                }\r\n            }\r\n\r\n            CollectionAssert.AreEqual(truth, list);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/UnsafeQueueTest.cs",
    "content": "﻿namespace Arch.LowLevel.Tests;\r\nusing static NUnit.Framework.Assert;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"UnsafeStack{T}\"/> related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class UnsafeQueueTest\r\n{\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeQueue{T}\"/> is capable of adding items.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueEnqueue()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n\r\n        for (var i = 0; i < 20; i++)\r\n            queue.Enqueue(i);\r\n        \r\n        That(queue, Has.Count.EqualTo(20));\r\n        That(queue.Peek(), Is.EqualTo(0));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeQueue{T}\"/> is capable of being converted into a span.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueAsSpan()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n\r\n        for (var i = 0; i < 9; i++)\r\n            queue.Enqueue(i);\r\n\r\n        var span = queue.AsSpan();\r\n\r\n        CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, span.ToArray());\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeQueue{T}\"/> is capable of peeking itemss.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueuePeek()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n        queue.Enqueue(1);\r\n        queue.Enqueue(2);\r\n\r\n        That(queue.Peek(), Is.EqualTo(1));\r\n        queue.Enqueue(3);\r\n        That(queue.Peek(), Is.EqualTo(1));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeQueue{T}\"/> is capable of popping itemss.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueDequeue()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n        queue.Enqueue(1);\r\n        queue.Enqueue(2);\r\n        queue.Enqueue(3);\r\n        \r\n        That(queue.Dequeue(), Is.EqualTo(1));\r\n        That(queue.Dequeue(), Is.EqualTo(2));\r\n        That(queue.Dequeue(), Is.EqualTo(3));\r\n\r\n        Throws<InvalidOperationException>(() =>\r\n        {\r\n            queue.Dequeue();\r\n        });\r\n\r\n        Throws<InvalidOperationException>(() =>\r\n        {\r\n            queue.Peek();\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public void UnsafeQueueClear()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n\r\n        for (var i = 0; i < 20; i++)\r\n            queue.Enqueue(i);\r\n\r\n        That(queue, Has.Count.EqualTo(20));\r\n\r\n        queue.Clear();\r\n\r\n        That(queue, Is.Empty);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeQueue{T}\"/> is capable of iterating with its enumerators.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueEnumerator()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n        queue.Enqueue(1);\r\n        queue.Enqueue(2);\r\n        queue.Enqueue(3);\r\n\r\n        // Ref iterator\r\n        var count = 0;\r\n        foreach (ref var item in queue)\r\n        {\r\n            count++;\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///      Checks if <see cref=\"UnsafeQueue{T}\"/> can be constructed with invalid parameters.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueInvalidConstruction()\r\n    {\r\n        Throws<ArgumentOutOfRangeException>(() =>\r\n        {\r\n            new UnsafeQueue<int>(-8);\r\n        });\r\n    }\r\n\r\n    /// <summary>\r\n    ///      Checks if <see cref=\"UnsafeQueue{T}\"/> EnsureCapacity functions correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueEnsureCapacity()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n\r\n        That(queue.Capacity, Is.AtLeast(8));\r\n\r\n        queue.EnsureCapacity(20);\r\n        That(queue.Capacity, Is.AtLeast(20));\r\n\r\n        queue.EnsureCapacity(10);\r\n        That(queue.Capacity, Is.AtLeast(20));\r\n    }\r\n\r\n    /// <summary>\r\n    ///      Checks if <see cref=\"UnsafeQueue{T}\"/> TrimExcess removes all excess capacity.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeQueueTrimExcess()\r\n    {\r\n        using var queue = new UnsafeQueue<int>(8);\r\n        for (var i = 0; i < 4; i++)\r\n            queue.Enqueue(i);\r\n\r\n        That(queue.Capacity, Is.AtLeast(8));\r\n\r\n        queue.EnsureCapacity(20);\r\n        That(queue.Capacity, Is.AtLeast(20));\r\n\r\n        queue.TrimExcess();\r\n\r\n        That(queue.Capacity, Is.EqualTo(4));\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/UnsafeStackTest.cs",
    "content": "﻿using System.Collections;\r\n\r\nnamespace Arch.LowLevel.Tests;\r\nusing static NUnit.Framework.Assert;\r\n\r\n/// <summary>\r\n///     Checks <see cref=\"UnsafeStack{T}\"/> related methods.\r\n/// </summary>\r\n[TestFixture]\r\npublic class UnsafeStackTest\r\n{\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> checks for invalid capacity on construction.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackInvalidCapacity()\r\n    {\r\n        Throws<ArgumentOutOfRangeException>(() => new UnsafeStack<int>(-9));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is capable of adding items.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackAdd()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n\r\n        That(stack.IsFull, Is.False);\r\n        That(stack.IsEmpty, Is.True);\r\n\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        That(stack.IsFull, Is.False);\r\n        That(stack.IsEmpty, Is.False);\r\n\r\n        That(stack.Count, Is.EqualTo(3));\r\n        That(stack.Peek(), Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is can be converted to a span\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackAsSpan()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        var span = stack.AsSpan();\r\n\r\n        stack.Pop();\r\n        stack.Push(4);\r\n\r\n        That(span.Length, Is.EqualTo(3));\r\n\r\n        CollectionAssert.AreEqual(span.ToArray(), new[] { 1, 2, 4 });\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is capable of adding items even past the initial capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackAddBeyondCapacity()\r\n    {\r\n        using var stack = new UnsafeStack<int>(4);\r\n        That(stack.Capacity, Is.EqualTo(4));\r\n\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n        stack.Push(4);\r\n        That(stack.IsFull, Is.True);\r\n        stack.Push(5);\r\n        stack.Push(6);\r\n        stack.Push(7);\r\n\r\n        That(stack.Count, Is.EqualTo(7));\r\n        That(stack.Peek(), Is.EqualTo(7));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}.EnsureCapacity\"/> expands capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackEnsureCapacityExpands()\r\n    {\r\n        using var stack = new UnsafeStack<int>(10);\r\n        That(stack.Capacity, Is.EqualTo(10));\r\n\r\n        stack.EnsureCapacity(11);\r\n\r\n        That(stack.Capacity, Is.GreaterThanOrEqualTo(11));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}.EnsureCapacity\"/> cannot shrink the capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackEnsureCapacityCannotShrink()\r\n    {\r\n        using var stack = new UnsafeStack<int>(10);\r\n        That(stack.Capacity, Is.EqualTo(10));\r\n\r\n        stack.EnsureCapacity(1);\r\n\r\n        That(stack.Capacity, Is.EqualTo(10));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}.EnsureCapacity\"/> can add a massive amount of new capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackEnsureCapacityExpandsALot()\r\n    {\r\n        using var stack = new UnsafeStack<int>(10);\r\n        That(stack.Capacity, Is.EqualTo(10));\r\n\r\n        stack.EnsureCapacity(10000);\r\n\r\n        That(stack.Capacity, Is.GreaterThanOrEqualTo(10000));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}.TrimExcess\"/> can remove unused capacity\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackTrimExcessShrinks()\r\n    {\r\n        using var stack = new UnsafeStack<int>(10);\r\n        That(stack.Capacity, Is.EqualTo(10));\r\n\r\n        stack.TrimExcess();\r\n\r\n        That(stack.Capacity, Is.LessThan(10));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}.TrimExcess\"/> does not expand\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackTrimExcessNeverExpands()\r\n    {\r\n        using var stack = new UnsafeStack<int>(2);\r\n        \r\n        stack.TrimExcess();\r\n\r\n        That(stack.Capacity, Is.LessThanOrEqualTo(2));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is capable of being cleared.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackClear()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        That(stack.Count, Is.EqualTo(3));\r\n        That(stack.Peek(), Is.EqualTo(3));\r\n\r\n        stack.Clear();\r\n\r\n        That(stack.Count, Is.EqualTo(0));\r\n        Throws<InvalidOperationException>(() => stack.Peek());\r\n        Throws<InvalidOperationException>(() => stack.Pop());\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is capable of peeking itemss.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackPeek()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n\r\n        That(stack.Peek(), Is.EqualTo(2));\r\n        stack.Push(3);\r\n        That(stack.Peek(), Is.EqualTo(3));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeStack{T}\"/> is capable of popping itemss.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackPop()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n        \r\n        That(stack.Pop(), Is.EqualTo(3));\r\n        That(stack.Pop(), Is.EqualTo(2));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of iterating with its enumerators.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackEnumerator()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        // Ref iterator\r\n        var count = 0;\r\n        foreach (ref var item in stack)\r\n        {\r\n            count++;\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the stack enumerator can be reset\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackEnumeratorReset()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        var enumerator = stack.GetEnumerator();\r\n\r\n        True(enumerator.MoveNext());\r\n        That(enumerator.Current, Is.EqualTo(3));\r\n        True(enumerator.MoveNext());\r\n        That(enumerator.Current, Is.EqualTo(2));\r\n\r\n        enumerator.Reset();\r\n\r\n        var count = 3;\r\n        foreach (var item in stack)\r\n        {\r\n            That(count, Is.EqualTo(item));\r\n            count--;\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if <see cref=\"UnsafeList{T}\"/> is capable of iterating with its enumerators.\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackIEnumerableTEnumerator()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        var enumerable = (IEnumerable<int>)stack;\r\n\r\n        var count = 0;\r\n        foreach (var item in enumerable)\r\n        {\r\n            count++;\r\n        }\r\n        That(count, Is.EqualTo(3));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if the stack enumerator can be reset\r\n    /// </summary>\r\n    [Test]\r\n    public void UnsafeStackIEnumerableEnumeratorReset()\r\n    {\r\n        using var stack = new UnsafeStack<int>(8);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n\r\n        var enumerator = ((IEnumerable)stack).GetEnumerator();\r\n\r\n        True(enumerator.MoveNext());\r\n        That(enumerator.Current, Is.EqualTo(3));\r\n        True(enumerator.MoveNext());\r\n        That(enumerator.Current, Is.EqualTo(2));\r\n\r\n        enumerator.Reset();\r\n\r\n        var count = 3;\r\n        foreach (var item in stack)\r\n        {\r\n            That(count, Is.EqualTo(item));\r\n            count--;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.LowLevel.Tests/Usings.cs",
    "content": "global using NUnit.Framework;"
  },
  {
    "path": "Arch.Persistence/Arch.Persistence.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <TargetFrameworks>net6.0;net7.0;netstandard2.1</TargetFrameworks>\r\n        <LangVersion>11</LangVersion>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <Title>Arch.Persistence</Title>\r\n        <Description>A Persistence-Framework for Arch.</Description>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n        <PackageReleaseNotes>Updated to Arch 2.1.0</PackageReleaseNotes>\r\n        <Version>2.1.0</Version>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n\r\n        <UnityPublish>true</UnityPublish>\r\n\r\n        <!-- Package 'MessagePack' 2.6.100-alpha has a known moderate severity vulnerability, https://github.com/advisories/GHSA-4qm4-8hg2-g2xm -->\r\n        <!-- For proper fix, consider upgrading to MessagePack v3 https://github.com/MessagePack-CSharp/MessagePack-CSharp/blob/master/doc/migrating_v2-v3.md -->\r\n        <NoWarn>NU1902</NoWarn>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n      <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n      <PackageReference Include=\"MessagePack\" Version=\"2.6.100-alpha\" />\r\n      <PackageReference Include=\"Utf8Json\" Version=\"1.3.7\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.Persistence/Binary.cs",
    "content": "﻿using Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Extensions.Dangerous;\r\nusing Arch.Core.Utils;\r\nusing Arch.LowLevel.Jagged;\r\nusing MessagePack;\r\nusing MessagePack.Formatters;\r\nusing System.Runtime.CompilerServices;\r\nusing Utf8Json;\r\n\r\nnamespace Arch.Persistence;\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"SingleEntityFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter\"/> to (de)serialize a single <see cref=\"Entity\"/>to or from json.\r\n/// </summary>\r\npublic partial class SingleEntityFormatter : IMessagePackFormatter<Entity>\r\n{\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Entity value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write id\r\n        writer.WriteInt32(value.Id);\r\n\r\n#if !PURE_ECS\r\n\r\n        // Write world\r\n        writer.WriteInt32(value.WorldId);\r\n#endif\r\n\r\n        // Write size\r\n        var componentTypes = value.GetComponentTypes();\r\n        writer.WriteInt32(componentTypes.Count);\r\n\r\n        // Write components\r\n        foreach (ref var type in componentTypes.Components)\r\n        {\r\n            // Write type\r\n            MessagePackSerializer.Serialize(ref writer, type, options);\r\n\r\n            // Write component\r\n            var cmp = value.Get(type);\r\n            MessagePackSerializer.Serialize(ref writer, cmp, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Entity Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Read id\r\n        var entityId = reader.ReadInt32();\r\n\r\n#if !PURE_ECS\r\n\r\n        // Read world id\r\n        var worldId = reader.ReadInt32();\r\n#endif\r\n\r\n        // Read size\r\n        var size = reader.ReadInt32();\r\n        var components = new object[size];\r\n\r\n        // Read components\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            // Read type\r\n            var type = MessagePackSerializer.Deserialize<ComponentType>(ref reader, options);\r\n            var cmp = MessagePackSerializer.Deserialize(type, ref reader, options);\r\n            components[index] = cmp!;\r\n        }\r\n\r\n        // Create the entity\r\n        var entity = EntityWorld.Create();\r\n        EntityWorld.AddRange(entity, components.AsSpan());\r\n        return entity;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"EntityFormatter\"/> class\r\n///     is a formatter that (de)serializes <see cref=\"Entity\"/> structs. \r\n/// </summary>\r\npublic partial class EntityFormatter : IMessagePackFormatter<Entity>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Entity value, MessagePackSerializerOptions options)\r\n    {\r\n        writer.WriteInt32(value.Id);\r\n        writer.WriteInt32(value.Version);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Entity Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Read id\r\n        var id = reader.ReadInt32();\r\n        var version = reader.ReadInt32();\r\n        return DangerousEntityExtensions.CreateEntityStruct(id, WorldId, version);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArrayFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Array}\"/> to (de)serialize <see cref=\"Array\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ArrayFormatter : IMessagePackFormatter<Array>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Array value, MessagePackSerializerOptions options)\r\n    {\r\n        var type = value.GetType().GetElementType();\r\n\r\n        // Write type and size\r\n        MessagePackSerializer.Serialize(ref writer, type, options);\r\n        writer.WriteUInt32((uint)value.Length);\r\n\r\n        // Write array\r\n        for (var index = 0; index < value.Length; index++)\r\n        {\r\n            var obj = value.GetValue(index);\r\n            MessagePackSerializer.Serialize(ref writer, obj, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Array Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Write type and size\r\n        var type = MessagePackSerializer.Deserialize<Type>(ref reader, options);\r\n        var size = reader.ReadUInt32();\r\n\r\n        // Create array\r\n        var array = Array.CreateInstance(type, size);\r\n\r\n        // Read array\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            var obj = MessagePackSerializer.Deserialize(type, ref reader, options);\r\n            array.SetValue(obj, index);\r\n        }\r\n        return array;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"JaggedArrayFormatter{T}\"/> class\r\n///     (de)serializes a <see cref=\"JaggedArray{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The type stored in the <see cref=\"JaggedArray{T}\"/>.</typeparam>\r\npublic partial class JaggedArrayFormatter<T> : IMessagePackFormatter<JaggedArray<T>>\r\n{\r\n    private const int CpuL1CacheSize = 16_384;\r\n    private readonly T _filler;\r\n\r\n    /// <summary>\r\n    /// Constructor.\r\n    /// </summary>\r\n    /// <param name=\"filler\">Filler.</param>\r\n    public JaggedArrayFormatter(T filler)\r\n    {\r\n        _filler = filler;\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, JaggedArray<T> value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write length/capacity and items\r\n        writer.WriteInt32(value.Capacity);\r\n        for (var index = 0; index < value.Capacity; index++)\r\n        {\r\n            var item = value[index];\r\n            MessagePackSerializer.Serialize(ref writer, item, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public JaggedArray<T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        var capacity = reader.ReadInt32();\r\n        var jaggedArray = new JaggedArray<T>(CpuL1CacheSize / Unsafe.SizeOf<T>(), _filler,capacity);\r\n\r\n        for (var index = 0; index < capacity; index++)\r\n        {\r\n            var item = MessagePackSerializer.Deserialize<T>(ref reader, options);\r\n            jaggedArray.Add(index, item);\r\n        }\r\n\r\n        return jaggedArray;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"ComponentType\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ComponentTypeFormatter : IMessagePackFormatter<ComponentType>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, ComponentType value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write id\r\n        writer.WriteUInt32((uint)value.Id);\r\n\r\n        // Write bytesize\r\n        writer.WriteUInt32((uint)value.ByteSize);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public ComponentType Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        var id = reader.ReadUInt32();\r\n        var bytesize = reader.ReadUInt32();\r\n\r\n        return new ComponentType((int)id, (int)bytesize);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"Signature\"/>s to or from json.\r\n/// </summary>\r\npublic partial class SignatureFormatter : IMessagePackFormatter<Signature>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Signature value, MessagePackSerializerOptions options)\r\n    {\r\n        var componentTypeFormatter = options.Resolver.GetFormatter<ComponentType>() as ComponentTypeFormatter;\r\n        \r\n        // Write count and types\r\n        writer.WriteUInt32((uint)value.Count);\r\n        foreach(var type in value.Components)\r\n        {\r\n            componentTypeFormatter!.Serialize(ref writer, type, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Signature Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        var componentTypeFormatter = options.Resolver.GetFormatter<ComponentType>() as ComponentTypeFormatter;\r\n        \r\n        // Read count\r\n        var count = reader.ReadUInt32();\r\n        \r\n        // Read types\r\n        var componentTypes = new ComponentType[count];\r\n        for (var index = 0; index < count; index++)\r\n        {\r\n            var componentType = componentTypeFormatter!.Deserialize(ref reader, options);\r\n            componentTypes[index] = componentType;\r\n        }\r\n        return new Signature(componentTypes);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"ComponentType\"/>s to or from json.\r\n/// </summary>\r\npublic partial class EntitySlotFormatter : IMessagePackFormatter<EntityData>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, EntityData value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write chunk index\r\n        writer.WriteUInt32((uint)value.Slot.ChunkIndex);\r\n\r\n        // Write entity index\r\n        writer.WriteUInt32((uint)value.Slot.Index);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public EntityData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        \r\n        // Read chunk index and entity index\r\n        var chunkIndex = reader.ReadUInt32();\r\n        var entityIndex = reader.ReadUInt32();\r\n\r\n        return new EntityData(null!, new Slot((int)entityIndex, (int)chunkIndex), 0);\r\n    }\r\n}\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"WorldFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{World}\"/> to (de)serialize <see cref=\"World\"/>s to or from json.\r\n/// </summary>\r\npublic partial class WorldFormatter : IMessagePackFormatter<World>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, World value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write important meta data\r\n        writer.WriteUInt32((uint)value.BaseChunkSize);\r\n        writer.WriteUInt32((uint)value.BaseChunkEntityCount);\r\n        \r\n        // Write slots\r\n        MessagePackSerializer.Serialize(ref writer, value.GetEntityDataArray(), options);\r\n\r\n        //Write recycled entity ids\r\n        var recycledEntityIDs = value.GetRecycledEntityIds();\r\n        MessagePackSerializer.Serialize(ref writer, recycledEntityIDs, options);\r\n\r\n        // Write archetypes\r\n        writer.WriteUInt32((uint)value.Archetypes.Count);\r\n        foreach (var archetype in value)\r\n        {\r\n            MessagePackSerializer.Serialize(ref writer, archetype, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public World Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Read important metadata\r\n        var baseChunkSize= reader.ReadUInt32();\r\n        var baseChunkEntityCount = reader.ReadUInt32();\r\n        \r\n        // Create world and setup formatter\r\n        var world = World.Create(chunkSizeInBytes: (int)baseChunkSize, minimumAmountOfEntitiesPerChunk: (int)baseChunkEntityCount);\r\n        var archetypeFormatter = options.Resolver.GetFormatter<Archetype>() as ArchetypeFormatter;\r\n        var entityFormatter = options.Resolver.GetFormatter<Entity>() as EntityFormatter;\r\n        entityFormatter!.WorldId = world.Id;\r\n        archetypeFormatter!.World = world;\r\n        \r\n        // Read slots\r\n        var slots = MessagePackSerializer.Deserialize<JaggedArray<EntityData>>(ref reader, options);\r\n\r\n        //Read recycled entity ids\r\n        var recycledEntityIDs = MessagePackSerializer.Deserialize<List<(int, int)>>(ref reader, options);\r\n\r\n        // Forward values to the world\r\n        world.SetRecycledEntityIds(recycledEntityIDs);\r\n        world.SetEntityDataArray(slots);\r\n        world.EnsureCapacity(slots.Capacity);\r\n        \r\n        // Read archetypes\r\n        var size = reader.ReadInt32();\r\n        List<Archetype> archetypes = new();\r\n\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            var archetype = archetypeFormatter.Deserialize(ref reader, options);\r\n            archetypes.Add(archetype);\r\n        }\r\n        \r\n        // Set archetypes\r\n        world.SetArchetypes(archetypes);\r\n        return world;\r\n    }\r\n}\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArchetypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Archetype}\"/> to (de)serialize <see cref=\"Archetype\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ArchetypeFormatter : IMessagePackFormatter<Archetype>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Archetype value, MessagePackSerializerOptions options)\r\n    {\r\n        // Setup formatters\r\n        var types = value.Signature;\r\n        var chunks = value.Chunks;\r\n        var chunkFormatter = options.Resolver.GetFormatter<Chunk>() as ChunkFormatter;\r\n        chunkFormatter!.Signature = types;\r\n        \r\n        // Write type array\r\n        MessagePackSerializer.Serialize(ref writer, types, options);\r\n\r\n        // Write lookup array\r\n        MessagePackSerializer.Serialize(ref writer, value.GetLookupArray(), options);\r\n\r\n        // Write chunk size\r\n        writer.WriteUInt32((uint)value.ChunkCount);\r\n\r\n        // Write chunks \r\n        for (var index = 0; index < value.ChunkCount; index++)\r\n        {\r\n            ref var chunk = ref chunks[index];\r\n            chunkFormatter.Serialize(ref writer, chunk, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Archetype Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n\r\n        var chunkFormatter = options.Resolver.GetFormatter<Chunk>() as ChunkFormatter;\r\n\r\n        // Types\r\n        var types = MessagePackSerializer.Deserialize<Signature>(ref reader, options);\r\n\r\n        // Archetype lookup array\r\n        var lookupArray = MessagePackSerializer.Deserialize<int[]>(ref reader, options);\r\n\r\n        // Archetype chunk size and list\r\n        var chunkSize = reader.ReadUInt32();\r\n\r\n        // Create archetype\r\n        var chunks = new List<Chunk>((int)chunkSize);\r\n        var archetype = DangerousArchetypeExtensions.CreateArchetype(World.BaseChunkSize, World.BaseChunkEntityCount, types);\r\n        archetype.Chunks.Clear(true);\r\n        archetype.SetCount((int)chunkSize - 1);\r\n\r\n        // Pass types and lookup array to the chunk formatter for saving performance and memory\r\n        chunkFormatter!.World = World;\r\n        chunkFormatter.Archetype = archetype;\r\n        chunkFormatter.Signature = types;\r\n        chunkFormatter.LookupArray = lookupArray;\r\n\r\n        // Deserialise each chunk and put it into the archetype. \r\n        var entities = 0;\r\n        for (var index = 0; index < chunkSize; index++)\r\n        {\r\n            var chunk = chunkFormatter.Deserialize(ref reader, options);\r\n            chunks.Add(chunk);\r\n            entities += chunk.Count;\r\n        }\r\n\r\n        archetype.SetChunks(chunks);\r\n        archetype.SetEntities(entities);\r\n        return archetype;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ChunkFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Chunk}\"/> to (de)serialize <see cref=\"Chunk\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ChunkFormatter : IMessagePackFormatter<Chunk>\r\n{\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref MessagePackWriter writer, Chunk value, MessagePackSerializerOptions options)\r\n    {\r\n        // Write size\r\n        writer.WriteUInt32((uint)value.Count);\r\n\r\n        // Write capacity\r\n        writer.WriteUInt32((uint)value.Capacity);\r\n\r\n        // Write entitys\r\n        MessagePackSerializer.Serialize(ref writer, value.Entities, options);\r\n\r\n        // Persist arrays as an array...\r\n        foreach(var type in Signature.Components)\r\n        {\r\n            // Write array itself\r\n            var array = value.GetArray(type);\r\n            MessagePackSerializer.Serialize(ref writer, array, options);\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IMessagePackFormatter{T}.Deserialize\"/>\r\n    public Chunk Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)\r\n    {\r\n        // Read chunk size\r\n        var size = reader.ReadUInt32();\r\n\r\n        // Read chunk size\r\n        var capacity = reader.ReadUInt32();\r\n\r\n        // Read entities\r\n        var entities = MessagePackSerializer.Deserialize<Entity[]>(ref reader, options);\r\n\r\n        // Create chunk\r\n        var chunk = DangerousChunkExtensions.CreateChunk((int)capacity, LookupArray, Signature);\r\n        entities.CopyTo(chunk.Entities, 0);\r\n        chunk.SetSize((int)size);\r\n\r\n        // Updating World.EntityInfoStorage to their new archetype\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            ref var entity = ref chunk.Entity(index);\r\n            entity = DangerousEntityExtensions.CreateEntityStruct(entity.Id, World.Id, entity.Version);\r\n            World.SetArchetype(entity, Archetype);\r\n        }\r\n\r\n        // Persist arrays as an array...\r\n        foreach(var type in Signature.Components)\r\n        {\r\n            // Read array of the type\r\n            var array = MessagePackSerializer.Deserialize<Array>(ref reader, options);\r\n            var chunkArray = chunk.GetArray(array.GetType().GetElementType()!);\r\n            Array.Copy(array, chunkArray, (int)size);\r\n        }\r\n\r\n        return chunk;\r\n    }\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "Arch.Persistence/Json.cs",
    "content": "﻿using Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Extensions.Dangerous;\r\nusing Arch.Core.Utils;\r\nusing Arch.LowLevel.Jagged;\r\nusing CommunityToolkit.HighPerformance;\r\nusing System.Runtime.CompilerServices;\r\nusing Utf8Json;\r\n\r\nnamespace Arch.Persistence;\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"SingleEntityFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Entity}\"/> to (de)serialize a single <see cref=\"Entity\"/>to or from json.\r\n/// </summary>\r\npublic partial class SingleEntityFormatter : IJsonFormatter<Entity>\r\n{\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"EntityWorld\"/> the entity belongs to. \r\n    /// </summary>\r\n    internal World EntityWorld { get; set; } = null!;\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Entity value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteBeginObject();\r\n\r\n        // Write id\r\n        writer.WritePropertyName(\"id\");\r\n        writer.WriteInt32(value.Id);\r\n        writer.WriteValueSeparator();\r\n\r\n#if !PURE_ECS\r\n\r\n        // Write world\r\n        writer.WritePropertyName(\"worldId\");\r\n        writer.WriteInt32(value.WorldId);\r\n        writer.WriteValueSeparator();\r\n\r\n#endif\r\n\r\n        // Write size\r\n        var componentTypes = value.GetComponentTypes();\r\n        writer.WritePropertyName(\"size\");\r\n        writer.WriteInt32(componentTypes.Count);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write components\r\n        writer.WritePropertyName(\"components\");\r\n        writer.WriteBeginArray();\r\n        foreach (ref var type in componentTypes.Components)\r\n        {\r\n            // Write type\r\n            writer.WriteBeginObject();\r\n            writer.WritePropertyName(\"type\");\r\n            JsonSerializer.Serialize(ref writer, type);\r\n            writer.WriteValueSeparator();\r\n\r\n            // Write component\r\n            writer.WritePropertyName(\"component\");\r\n            var cmp = value.Get(type);\r\n            JsonSerializer.NonGeneric.Serialize(ref writer, cmp, formatterResolver);\r\n            writer.WriteEndObject();\r\n            writer.WriteValueSeparator();\r\n        }\r\n        writer.AdvanceOffset(-1);\r\n\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Entity Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Read id\r\n        reader.ReadPropertyName();\r\n        var entityId = reader.ReadInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n#if !PURE_ECS\r\n\r\n        // Read world id\r\n        reader.ReadPropertyName();\r\n        var worldId = reader.ReadInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n#endif\r\n\r\n        // Read size\r\n        reader.ReadPropertyName();\r\n        var size = reader.ReadInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        var components = new object[size];\r\n        var count = 0;\r\n\r\n        // Read components\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count))\r\n        {\r\n            reader.ReadIsBeginObject();\r\n\r\n            // Read type\r\n            reader.ReadPropertyName();\r\n            var type = JsonSerializer.Deserialize<ComponentType>(ref reader);\r\n            reader.ReadIsValueSeparator();\r\n\r\n            reader.ReadPropertyName();\r\n            var cmp = JsonSerializer.NonGeneric.Deserialize(type.Type, ref reader, formatterResolver);\r\n            components[count - 1] = cmp;\r\n            reader.ReadIsEndObject();\r\n        }\r\n\r\n        // Creat the entity\r\n        var entity = EntityWorld.Create();\r\n        EntityWorld.AddRange(entity, components.AsSpan());\r\n\r\n        reader.ReadIsEndObject();\r\n        return entity;\r\n    }\r\n}\r\n\r\npublic partial class EntityFormatter : IJsonFormatter<Entity>\r\n{\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"World.Id\"/> all deserialized <see cref=\"Entity\"/>s will belong to.\r\n    ///     <remarks>Due to the nature of deserialisation and changing world landscape we need to assign new WorldIds to the deserialized entities.</remarks>\r\n    /// </summary>\r\n    internal int WorldId { get; set; }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Entity value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteInt32(value.Id);\r\n        writer.WriteValueSeparator();\r\n        writer.WriteInt32(value.Version);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Entity Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        // Read id\r\n        var id = reader.ReadInt32();\r\n        reader.ReadIsValueSeparator();\r\n        var version = reader.ReadInt32();\r\n        return DangerousEntityExtensions.CreateEntityStruct(id, WorldId, version);\r\n    }\r\n}\r\n\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArrayFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Array}\"/> to (de)serialize <see cref=\"Array\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ArrayFormatter : IJsonFormatter<Array>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Array value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        var type = value.GetType().GetElementType();\r\n\r\n        // Write type and size\r\n        writer.WriteBeginObject();\r\n        writer.WritePropertyName(\"type\");\r\n        JsonSerializer.Serialize(ref writer, type, formatterResolver);\r\n        writer.WriteValueSeparator();\r\n\r\n        writer.WritePropertyName(\"length\");\r\n        writer.WriteUInt32((uint)value.Length);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write array\r\n        writer.WritePropertyName(\"items\");\r\n        writer.WriteBeginArray();\r\n        for (var index = 0; index < value.Length; index++)\r\n        {\r\n            var obj = value.GetValue(index);\r\n            JsonSerializer.NonGeneric.Serialize(ref writer, obj, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n        writer.AdvanceOffset(-1);\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Array Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        // Write type and size\r\n        reader.ReadIsBeginObject();\r\n        reader.ReadPropertyName();\r\n        var type = JsonSerializer.Deserialize<Type>(ref reader, formatterResolver);\r\n        reader.ReadIsValueSeparator();\r\n\r\n        reader.ReadPropertyName();\r\n        var size = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Create array\r\n        var array = Array.CreateInstance(type, size);\r\n\r\n        // Read array\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            var obj = JsonSerializer.NonGeneric.Deserialize(type, ref reader, formatterResolver);\r\n            array.SetValue(obj, index);\r\n            reader.ReadIsValueSeparator();\r\n        }\r\n        reader.ReadIsEndArray();\r\n        reader.ReadIsEndObject();\r\n        return array;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"JaggedArrayFormatter{T}\"/> class\r\n///     (de)serializes a <see cref=\"JaggedArray{T}\"/>.\r\n/// </summary>\r\npublic partial class JaggedArrayFormatter<T> : IJsonFormatter<JaggedArray<T>>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, JaggedArray<T> value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteBeginObject();\r\n\r\n        // Write length/capacity and items\r\n        writer.WritePropertyName(\"capacity\");\r\n        writer.WriteInt32(value.Capacity);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write items\r\n        writer.WritePropertyName(\"items\");\r\n        writer.WriteBeginArray();\r\n\r\n        for (var index = 0; index < value.Capacity; index++)\r\n        {\r\n            var item = value[index];\r\n            JsonSerializer.Serialize(ref writer, item, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n\r\n        // Cut last value seperator\r\n        if (value.Capacity > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public JaggedArray<T> Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Read capacity;\r\n        reader.ReadPropertyName();\r\n        var capacity = reader.ReadInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Read items\r\n        var jaggedArray = new JaggedArray<T>(CpuL1CacheSize / Unsafe.SizeOf<T>(), _filler,capacity);\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        for (var index = 0; index < capacity; index++)\r\n        {\r\n            var item = JsonSerializer.Deserialize<T>(ref reader, formatterResolver);\r\n            jaggedArray.Add(index, item);\r\n            reader.ReadIsValueSeparator();\r\n        }\r\n        reader.ReadIsEndArray();\r\n        reader.ReadIsEndObject();\r\n\r\n        return jaggedArray;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"ComponentType\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ComponentTypeFormatter : IJsonFormatter<ComponentType>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, ComponentType value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteBeginObject();\r\n\r\n        // Write id\r\n        writer.WritePropertyName(\"id\");\r\n        writer.WriteUInt32((uint)value.Id);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write bytesize\r\n        writer.WritePropertyName(\"byteSize\");\r\n        writer.WriteUInt32((uint)value.ByteSize);\r\n\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public ComponentType Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n\r\n        reader.ReadPropertyName();\r\n        var id = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        reader.ReadPropertyName();\r\n        var bytesize = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        reader.ReadIsEndObject();\r\n\r\n        return new ComponentType((int)id, (int)bytesize);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"Signature\"/>s to or from json.\r\n/// </summary>\r\npublic partial class SignatureFormatter : IJsonFormatter<Signature>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Signature value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        var componentTypeFormatter = formatterResolver.GetFormatter<ComponentType>() as ComponentTypeFormatter;\r\n\r\n        writer.WriteBeginObject();\r\n\r\n        // write Count\r\n        writer.WritePropertyName(\"count\");\r\n        writer.WriteUInt32((uint)value.Count);\r\n        writer.WriteValueSeparator();\r\n        \r\n        // Write components\r\n        writer.WritePropertyName(\"components\");\r\n        writer.WriteBeginArray();\r\n        \r\n        foreach (var type in value.Components)\r\n        {\r\n            componentTypeFormatter!.Serialize(ref writer, type, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n        \r\n        // Cut last value seperator\r\n        if (value.Count > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n        \r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Signature Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        var componentTypeFormatter = formatterResolver.GetFormatter<ComponentType>() as ComponentTypeFormatter;\r\n        \r\n        reader.ReadIsBeginObject();\r\n        reader.ReadPropertyName();\r\n        \r\n        // Read count\r\n        var count = (int)reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        // Read types\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        \r\n        var componentTypes = new ComponentType[count];\r\n        count = 0;\r\n        while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count))\r\n        {\r\n            var archetype = componentTypeFormatter!.Deserialize(ref reader, formatterResolver);\r\n            componentTypes[count - 1] = (archetype);\r\n        }\r\n\r\n        // Set archetypes\r\n        reader.ReadIsEndObject();\r\n        return new Signature(componentTypes);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ComponentTypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{ComponentType}\"/> to (de)serialize <see cref=\"ComponentType\"/>s to or from json.\r\n/// </summary>\r\npublic partial class EntitySlotFormatter : IJsonFormatter<EntityData>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, EntityData value, IJsonFormatterResolver options)\r\n    {\r\n        writer.WriteBeginObject();\r\n        \r\n        // Write chunk index\r\n        writer.WritePropertyName(\"chunkIndex\");\r\n        writer.WriteUInt32((uint)value.Slot.ChunkIndex);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write entity index\r\n        writer.WritePropertyName(\"index\");\r\n        writer.WriteUInt32((uint)value.Slot.Index);\r\n        \r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public EntityData Deserialize(ref JsonReader reader, IJsonFormatterResolver options)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Read chunk index\r\n        reader.ReadPropertyName();\r\n        var chunkIndex = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        // Read entity index\r\n        reader.ReadPropertyName();\r\n        var entityIndex = reader.ReadUInt32();\r\n\r\n        reader.ReadIsEndObject();\r\n        return new EntityData(null!, new Slot((int)entityIndex, (int)chunkIndex), 0);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"WorldFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{World}\"/> to (de)serialize <see cref=\"World\"/>s to or from json.\r\n/// </summary>\r\npublic partial class WorldFormatter : IJsonFormatter<World>\r\n{\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, World value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        //var archetypeFormatter = formatterResolver.GetFormatter<Archetype>();\r\n        //var versionsFormatter = formatterResolver.GetFormatter<int[][]>();\r\n        //var slotFormatter = formatterResolver.GetFormatter<(int,int)[][]>();\r\n\r\n        writer.WriteBeginObject();\r\n\r\n        // Write meta data\r\n        writer.WritePropertyName(\"baseChunkSize\");\r\n        writer.WriteUInt32((uint)value.BaseChunkSize);\r\n        writer.WriteValueSeparator();\r\n        \r\n        writer.WritePropertyName(\"baseChunkEntityCount\");\r\n        writer.WriteUInt32((uint)value.BaseChunkEntityCount);\r\n        writer.WriteValueSeparator();\r\n        \r\n        // Write slots\r\n        writer.WritePropertyName(\"slots\");\r\n        JsonSerializer.Serialize(ref writer, value.GetEntityDataArray(), formatterResolver);\r\n        writer.WriteValueSeparator();\r\n\r\n        //Write recycled entity ids\r\n        writer.WritePropertyName(\"recycledEntityIDs\");\r\n        writer.WriteBeginArray();\r\n        var recycledEntityIDs = value.GetRecycledEntityIds();\r\n        foreach (var recycledId in recycledEntityIDs)\r\n        {\r\n            writer.WriteBeginObject();\r\n            writer.WritePropertyName(\"id\");\r\n            writer.WriteInt32(recycledId.Item1);\r\n            writer.WriteValueSeparator();\r\n            writer.WritePropertyName(\"version\");\r\n            writer.WriteInt32(recycledId.Item2);\r\n            writer.WriteEndObject();\r\n\r\n            writer.WriteValueSeparator();\r\n        }\r\n        // Cut last value seperator\r\n        if (recycledEntityIDs.Count > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n        writer.WriteEndArray();\r\n\r\n        writer.WriteValueSeparator();\r\n\r\n        //Write archetypes\r\n        writer.WritePropertyName(\"archetypes\");\r\n        writer.WriteBeginArray();\r\n        foreach (var archetype in value)\r\n        {\r\n            JsonSerializer.Serialize(ref writer, archetype, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n\r\n        // Cut last value seperator\r\n        if (value.Archetypes.Count > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public World Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        // Create world and setup formatter\r\n        var archetypeFormatter = formatterResolver.GetFormatter<Archetype>() as ArchetypeFormatter;\r\n        var entityFormatter = formatterResolver.GetFormatter<Entity>() as EntityFormatter;\r\n\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Read meta data\r\n        reader.ReadPropertyName();\r\n        var baseChunkSize = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        reader.ReadPropertyName();\r\n        var baseChunkEntityCount = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        // Construct world\r\n        var world = World.Create(chunkSizeInBytes: (int)baseChunkSize, minimumAmountOfEntitiesPerChunk: (int)baseChunkEntityCount);\r\n        entityFormatter!.WorldId = world.Id;\r\n        archetypeFormatter!.World = world;\r\n        \r\n        // Read slots\r\n        reader.ReadPropertyName();\r\n        var slots = JsonSerializer.Deserialize<JaggedArray<EntityData>>(ref reader, formatterResolver);\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Read recycled ids\r\n        var count = 0;\r\n        List<(int, int)> recycledIds = new();\r\n\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n\r\n        while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count))\r\n        {\r\n            reader.ReadIsBeginObject();\r\n            reader.ReadPropertyName();\r\n            var id = reader.ReadInt32();\r\n            reader.ReadIsValueSeparator();\r\n            reader.ReadPropertyName();\r\n            var value = reader.ReadInt32();\r\n            reader.ReadIsEndObject();\r\n\r\n            (int, int) recycledId = new(id, value);\r\n\r\n            recycledIds.Add(recycledId);\r\n        }\r\n\r\n        reader.ReadIsValueSeparator();\r\n        \r\n        // Forward values to the world\r\n        world.SetRecycledEntityIds(recycledIds);\r\n        world.SetEntityDataArray(slots);\r\n        world.EnsureCapacity(slots.Capacity);\r\n\r\n        // Read archetypes\r\n        count = 0;\r\n        List<Archetype> archetypes = new();\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count))\r\n        {\r\n            var archetype = archetypeFormatter.Deserialize(ref reader, formatterResolver);\r\n            archetypes.Add(archetype);\r\n        }\r\n\r\n        // Set archetypes\r\n        world.SetArchetypes(archetypes);\r\n        reader.ReadIsEndObject();\r\n        return world;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArchetypeFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Archetype}\"/> to (de)serialize <see cref=\"Archetype\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ArchetypeFormatter : IJsonFormatter<Archetype>\r\n{\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"World\"/> which is being used by this formatter during serialisation/deserialisation. \r\n    /// </summary>\r\n    internal World World { get; set; } = null!;\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Archetype value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        // Setup formatters\r\n        var types = value.Signature;\r\n        var chunks = value.Chunks;\r\n        var chunkFormatter = formatterResolver.GetFormatter<Chunk>() as ChunkFormatter;\r\n        chunkFormatter!.Signature = types;\r\n\r\n        writer.WriteBeginObject();\r\n\r\n        // Write type array\r\n        writer.WritePropertyName(\"types\");\r\n        JsonSerializer.Serialize(ref writer, types, formatterResolver);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write lookup array\r\n        writer.WritePropertyName(\"lookup\");\r\n        JsonSerializer.Serialize(ref writer, value.GetLookupArray(), formatterResolver);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write chunk size\r\n        writer.WritePropertyName(\"chunkCount\");\r\n        writer.WriteUInt32((uint)value.ChunkCount);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write chunks \r\n        writer.WritePropertyName(\"chunks\");\r\n        writer.WriteBeginArray();\r\n        for (var index = 0; index < value.ChunkCount; index++)\r\n        {\r\n            ref var chunk = ref chunks[index];\r\n            chunkFormatter.Serialize(ref writer, chunk, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n\r\n        // Trim last value separator\r\n        if (value.ChunkCount > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Archetype Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        var chunkFormatter = formatterResolver.GetFormatter<Chunk>() as ChunkFormatter;\r\n\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Types\r\n        reader.ReadPropertyName();\r\n        var types = JsonSerializer.Deserialize<Signature>(ref reader, formatterResolver);\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Archetype lookup array\r\n        reader.ReadPropertyName();\r\n        var lookupArray = JsonSerializer.Deserialize<int[]>(ref reader, formatterResolver);\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Archetype chunk size and list\r\n        reader.ReadPropertyName();\r\n        var chunkCount = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Create archetype\r\n        var chunks = new List<Chunk>((int)chunkCount);\r\n        var archetype = DangerousArchetypeExtensions.CreateArchetype(World.BaseChunkSize, World.BaseChunkEntityCount, types);\r\n        archetype.Chunks.Clear(true);\r\n        archetype.SetCount((int)chunkCount - 1);\r\n\r\n        // Pass types and lookup array to the chunk formatter for saving performance and memory\r\n        chunkFormatter!.World = World;\r\n        chunkFormatter.Archetype = archetype;\r\n        chunkFormatter.Signature = types;\r\n        chunkFormatter.LookupArray = lookupArray;\r\n\r\n        // Deserialise each chunk and put it into the archetype. \r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n\r\n        var entities = 0;\r\n        for (var index = 0; index < chunkCount; index++)\r\n        {\r\n            var chunk = chunkFormatter.Deserialize(ref reader, formatterResolver);\r\n            chunks.Add(chunk);\r\n            entities += chunk.Count;\r\n            reader.ReadIsValueSeparator();\r\n        }\r\n        \r\n        archetype.SetChunks(chunks);\r\n        archetype.SetEntities(entities);\r\n\r\n        reader.ReadIsEndArray();\r\n        reader.ReadIsEndObject();\r\n        return archetype;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ChunkFormatter\"/> class\r\n///     is a <see cref=\"IJsonFormatter{Chunk}\"/> to (de)serialize <see cref=\"Chunk\"/>s to or from json.\r\n/// </summary>\r\npublic partial class ChunkFormatter : IJsonFormatter<Chunk>\r\n{\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"Archetype\"/> the current (de)serialized <see cref=\"Chunk\"/> belongs to.\r\n    ///     Since chunks do not know this, we need to pass this information along it. \r\n    /// </summary>\r\n    internal World World { get; set; } = null!;\r\n\r\n    /// <summary>\r\n    ///     The <see cref=\"Archetype\"/> the current (de)serialized <see cref=\"Chunk\"/> belongs to.\r\n    ///     Since chunks do not know this, we need to pass this information along it. \r\n    /// </summary>\r\n    internal Archetype Archetype { get; set; } = null!;\r\n\r\n    /// <summary>\r\n    ///     The types used in the <see cref=\"Chunk\"/> in each <see cref=\"Chunk\"/> (de)serialized by this formatter.\r\n    ///     <remarks>Since <see cref=\"Chunk\"/> does not have a reference to them and its controlled by its <see cref=\"Archetype\"/>.</remarks>\r\n    /// </summary>\r\n    internal Signature Signature { get; set; } = Signature.Null;\r\n\r\n    /// <summary>\r\n    ///     The lookup array used by each <see cref=\"Chunk\"/> (de)serialized by this formatter.\r\n    ///     <remarks>Since <see cref=\"Chunk\"/> does not have a reference to them and its controlled by its <see cref=\"Archetype\"/>.</remarks>\r\n    /// </summary>\r\n    internal int[] LookupArray { get; set; } = Array.Empty<int>();\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Serialize\"/>\r\n    public void Serialize(ref JsonWriter writer, Chunk value, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        writer.WriteBeginObject();\r\n\r\n        // Write size\r\n        writer.WritePropertyName(\"count\");\r\n        writer.WriteUInt32((uint)value.Count);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write capacity\r\n        writer.WritePropertyName(\"capacity\");\r\n        writer.WriteUInt32((uint)value.Capacity);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Write entitys\r\n        writer.WritePropertyName(\"entities\");\r\n        JsonSerializer.NonGeneric.Serialize(ref writer, value.Entities, formatterResolver);\r\n        writer.WriteValueSeparator();\r\n\r\n        // Persist arrays as an array...\r\n        writer.WritePropertyName(\"arrays\");\r\n        writer.WriteBeginArray();\r\n        foreach(var type in Signature.Components)\r\n        {\r\n            // Write array itself\r\n            var array = value.GetArray(type);\r\n            JsonSerializer.Serialize(ref writer, array, formatterResolver);\r\n            writer.WriteValueSeparator();\r\n        }\r\n\r\n        // Remove trailing \r\n        if (Signature.Count > 0)\r\n        {\r\n            writer.AdvanceOffset(-1);\r\n        }\r\n\r\n        writer.WriteEndArray();\r\n        writer.WriteEndObject();\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IJsonFormatter{T}.Deserialize\"/>\r\n    public Chunk Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)\r\n    {\r\n        reader.ReadIsBeginObject();\r\n\r\n        // Read chunk size\r\n        reader.ReadPropertyName();\r\n        var size = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Read chunk size\r\n        reader.ReadPropertyName();\r\n        var capacity = reader.ReadUInt32();\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Read entities\r\n        reader.ReadPropertyName();\r\n        var entities = JsonSerializer.Deserialize<Entity[]>(ref reader, formatterResolver);\r\n        reader.ReadIsValueSeparator();\r\n\r\n        // Create chunk\r\n        var chunk = DangerousChunkExtensions.CreateChunk((int)capacity, LookupArray, Signature);\r\n        entities.CopyTo(chunk.Entities, 0);\r\n        chunk.SetSize((int)size);\r\n\r\n        // Updating World.EntityInfoStorage to their new archetype\r\n        for (var index = 0; index < size; index++)\r\n        {\r\n            ref var entity = ref chunk.Entity(index);\r\n            entity = DangerousEntityExtensions.CreateEntityStruct(entity.Id, World.Id, entity.Version);\r\n            World.SetArchetype(entity, Archetype);\r\n        }\r\n\r\n        // Persist arrays as an array...\r\n        reader.ReadPropertyName();\r\n        reader.ReadIsBeginArray();\r\n        foreach(var type in Signature)\r\n        {\r\n            // Read array of the type\r\n            var array = JsonSerializer.Deserialize<Array>(ref reader, formatterResolver);\r\n            var chunkArray = chunk.GetArray(array.GetType().GetElementType()!);\r\n            Array.Copy(array, chunkArray, (int)size);\r\n            reader.ReadIsValueSeparator();\r\n        }\r\n\r\n        reader.ReadIsEndArray();\r\n        reader.ReadIsEndObject();\r\n        return chunk;\r\n    }\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "Arch.Persistence/Serializer.cs",
    "content": "﻿using Arch.Core;\r\nusing MessagePack;\r\nusing MessagePack.Formatters;\r\nusing System.Buffers;\r\nusing Utf8Json;\r\nusing Utf8Json.Resolvers;\r\nusing DateTimeFormatter = Utf8Json.Formatters.DateTimeFormatter;\r\nusing NullableDateTimeFormatter = Utf8Json.Formatters.NullableDateTimeFormatter;\r\n\r\nnamespace Arch.Persistence;\r\n\r\n/// <summary>\r\n///     The <see cref=\"IArchSerializer\"/> interface\r\n///     represents an interface with shared methods to (de)serialize worlds and entities.\r\n///     <remarks>It might happen that the serialized object is too large to fit into a regular c# byte-array. In this case use the <see cref=\"IBufferWriter{T}\"/>-API.</remarks>\r\n/// </summary>\r\npublic interface IArchSerializer\r\n{\r\n    /// <summary>\r\n    ///     Serializes an <see cref=\"Entity\"/> to a <see cref=\"byte\"/>-array.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    byte[] Serialize(World world, Entity entity);\r\n\r\n    /// <summary>\r\n    ///     Serializes an <see cref=\"Entity\"/> to a <see cref=\"Stream\"/> e.g. a File or existing array.\r\n    /// </summary>\r\n    /// <param name=\"stream\">The <see cref=\"Stream\"/>.</param>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    void Serialize(Stream stream, World world, Entity entity);\r\n\r\n    /// <summary>\r\n    ///     Serializes an <see cref=\"Entity\"/> to a <see cref=\"IBufferWriter{T}\"/> e.g. a File or existing array.\r\n    /// </summary>\r\n    /// <param name=\"writer\">The <see cref=\"IBufferWriter{T}\"/>.</param>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    void Serialize(IBufferWriter<byte> writer, World world, Entity entity);\r\n\r\n    /// <summary>\r\n    ///     Deserializes an <see cref=\"Entity\"/> from its bytes to an real <see cref=\"Entity\"/> in a <see cref=\"World\"/>.\r\n    ///     <remarks>The new <see cref=\"Entity.Id\"/> and <see cref=\"Entity.WorldId\"/> will differ.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <returns></returns>\r\n    Entity Deserialize(World world, byte[] entity);\r\n\r\n    /// <summary>\r\n    ///     Deserializes an <see cref=\"Entity\"/> from its bytes to an real <see cref=\"Entity\"/> in a <see cref=\"World\"/>.\r\n    ///     <remarks>The new <see cref=\"Entity.Id\"/> and <see cref=\"Entity.WorldId\"/> will differ.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"stream\">The <see cref=\"Stream\"/>.</param>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    /// <returns></returns>\r\n    Entity Deserialize(Stream stream, World world);\r\n\r\n    /// <summary>\r\n    ///     Serializes a <see cref=\"World\"/> to a <see cref=\"byte\"/>-array.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    byte[] Serialize(World world);\r\n\r\n    /// <summary>\r\n    ///     Serializes a <see cref=\"World\"/> to a <see cref=\"Stream\"/>.\r\n    /// </summary>\r\n    /// <param name=\"stream\">The <see cref=\"Stream\"/>.</param>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    void Serialize(Stream stream, World world);\r\n\r\n    /// <summary>\r\n    ///     Serializes a <see cref=\"World\"/> to a <see cref=\"IBufferWriter{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"writer\">The <see cref=\"IBufferWriter{T}\"/>.</param>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    void Serialize(IBufferWriter<byte> writer, World world);\r\n\r\n    /// <summary>\r\n    ///     Deserializes a byte-array into a <see cref=\"World\"/>.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> as an byte-array.</param>\r\n    /// <returns>The new <see cref=\"World\"/>.</returns>\r\n    World Deserialize(byte[] world);\r\n\r\n    /// <summary>\r\n    ///     Deserializes a byte-array into a <see cref=\"World\"/>.\r\n    /// </summary>\r\n    /// <param name=\"stream\">The <see cref=\"Stream\"/>.</param>\r\n    /// <returns>The new <see cref=\"World\"/>.</returns>\r\n    World Deserialize(Stream stream);\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArchBinarySerializer\"/> class\r\n///     represents a binary serializer for arch to (de)serialize single entities and whole worlds by binary. \r\n/// </summary>\r\npublic class ArchBinarySerializer : IArchSerializer\r\n{\r\n    /// <summary>\r\n    ///     The default formatters used to (de)serialize the <see cref=\"World\"/>.\r\n    /// </summary>\r\n    private readonly IMessagePackFormatter[] _formatters =\r\n    {\r\n        new WorldFormatter(),\r\n        new ArchetypeFormatter(),\r\n        new ChunkFormatter(),\r\n        new ArrayFormatter(),\r\n        new ComponentTypeFormatter(),\r\n        new SignatureFormatter(),\r\n        new EntitySlotFormatter(),\r\n        new EntityFormatter(),\r\n        new JaggedArrayFormatter<int>(-1),\r\n        new JaggedArrayFormatter<(int,int)>((-1,-1)),\r\n        new JaggedArrayFormatter<EntityData>(new EntityData(null!, new Slot(-1,-1), -1))\r\n    };\r\n\r\n    /// <summary>\r\n    ///     The default formatters used to (de)serialize a single <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    private readonly IMessagePackFormatter[] _singleEntityFormatters =\r\n    {\r\n        new ComponentTypeFormatter(),\r\n        new SignatureFormatter(),\r\n        new SingleEntityFormatter()\r\n    };\r\n\r\n    /// <summary>\r\n    ///     The standard <see cref=\"MessagePackSerializerOptions\"/> for world (de)serialization.\r\n    /// </summary>\r\n    private readonly MessagePackSerializerOptions _options;\r\n\r\n    /// <summary>\r\n    ///     The standard <see cref=\"MessagePackSerializerOptions\"/> for single entity (de)serialization.\r\n    /// </summary>\r\n    private readonly MessagePackSerializerOptions _singleEntityOptions;\r\n\r\n    /// <summary>\r\n    ///     The static constructor gets called during compile time to setup the serializer. \r\n    /// </summary>\r\n    public ArchBinarySerializer(params IMessagePackFormatter[] custFormatters)\r\n    {\r\n        // Register all important jsonformatters \r\n        _options = MessagePackSerializerOptions.Standard.WithResolver(\r\n            MessagePack.Resolvers.CompositeResolver.Create(\r\n                _formatters.Concat(custFormatters).ToList(),\r\n                new List<IFormatterResolver>\r\n                {\r\n                    MessagePack.Resolvers.BuiltinResolver.Instance,\r\n                    MessagePack.Resolvers.ContractlessStandardResolverAllowPrivate.Instance\r\n                }\r\n            )\r\n        );\r\n\r\n        _singleEntityOptions = MessagePackSerializerOptions.Standard.WithResolver(\r\n            MessagePack.Resolvers.CompositeResolver.Create(\r\n                _singleEntityFormatters.Concat(custFormatters).ToList(),\r\n                new List<IFormatterResolver>\r\n                {\r\n                    MessagePack.Resolvers.BuiltinResolver.Instance,\r\n                    MessagePack.Resolvers.ContractlessStandardResolverAllowPrivate.Instance\r\n                }\r\n            )\r\n        );\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public byte[] Serialize(World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return MessagePackSerializer.Serialize(entity, _singleEntityOptions);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(Stream stream, World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        MessagePackSerializer.Serialize(stream, entity, _singleEntityOptions);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(IBufferWriter<byte> writer, World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        MessagePackSerializer.Serialize(writer, entity, _singleEntityOptions);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public Entity Deserialize(World world, byte[] entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return MessagePackSerializer.Deserialize<Entity>(entity, _singleEntityOptions);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public Entity Deserialize(Stream stream, World world)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return MessagePackSerializer.Deserialize<Entity>(stream, _singleEntityOptions);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public byte[] Serialize(World world)\r\n    {\r\n        return MessagePackSerializer.Serialize(world, _options); ;\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(Stream stream, World world)\r\n    {\r\n        MessagePackSerializer.Serialize(stream, world, _options);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(IBufferWriter<byte> writer, World world)\r\n    {\r\n        MessagePackSerializer.Serialize(writer, world, _options);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public World Deserialize(byte[] world)\r\n    {\r\n        return MessagePackSerializer.Deserialize<World>(world, _options);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public World Deserialize(Stream stream)\r\n    {\r\n        return MessagePackSerializer.Deserialize<World>(stream, _options);\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"ArchJsonSerializer\"/> class\r\n///     represents a json serializer for arch to (de)serialize single entities and whole worlds by binary. \r\n/// </summary>\r\npublic class ArchJsonSerializer : IArchSerializer\r\n{\r\n\r\n    /// <summary>\r\n    ///     The default formatters used to (de)serialize the <see cref=\"World\"/>.\r\n    /// </summary>\r\n    private readonly IJsonFormatter[] _formatters = {\r\n        new WorldFormatter(),\r\n        new ArchetypeFormatter(),\r\n        new ChunkFormatter(),\r\n        new ArrayFormatter(),\r\n        new ComponentTypeFormatter(),\r\n        new SignatureFormatter(),\r\n        new EntitySlotFormatter(),\r\n        new EntityFormatter(),\r\n        new JaggedArrayFormatter<int>(-1),\r\n        new JaggedArrayFormatter<(int,int)>((-1,-1)),\r\n        new JaggedArrayFormatter<EntityData>(new EntityData(null!, new Slot(-1, -1), -1)),\r\n        new DateTimeFormatter(\"yyyy-MM-dd HH:mm:ss\"),\r\n        new NullableDateTimeFormatter(\"yyyy-MM-dd HH:mm:ss\")\r\n    };\r\n\r\n    /// <summary>\r\n    ///     The default formatters used to (de)serialize a single <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    private readonly IJsonFormatter[] _singleEntityFormatters =\r\n    {\r\n        new ComponentTypeFormatter(),\r\n        new SignatureFormatter(),\r\n        new SingleEntityFormatter(),\r\n        new DateTimeFormatter(\"yyyy-MM-dd HH:mm:ss\"),\r\n        new NullableDateTimeFormatter(\"yyyy-MM-dd HH:mm:ss\")\r\n    };\r\n\r\n    // It can `not` garbage collect and create is slightly high cost.\r\n    // so you should store to static field.\r\n    private IJsonFormatterResolver _formatterResolver;\r\n\r\n    // CompositeResolver.Create can create dynamic composite resolver.\r\n    // It can `not` garbage collect and create is slightly high cost.\r\n    // so you should store to static field.\r\n    private IJsonFormatterResolver _singleEntityFormatterResolver;\r\n\r\n    /// <summary>\r\n    ///     The static constructor gets called during compile time to setup the serializer. \r\n    /// </summary>\r\n    public ArchJsonSerializer(params IJsonFormatter[] custFormatters)\r\n    {\r\n        // Register all important jsonformatters \r\n        _formatterResolver = CompositeResolver.Create(\r\n            _formatters.Concat(custFormatters).ToArray(),\r\n            new[] {\r\n                EnumResolver.UnderlyingValue,\r\n                StandardResolver.AllowPrivateExcludeNullSnakeCase,\r\n                BuiltinResolver.Instance,\r\n                DynamicGenericResolver.Instance,\r\n            }\r\n        );\r\n\r\n        _singleEntityFormatterResolver = CompositeResolver.Create(\r\n            _singleEntityFormatters.Concat(custFormatters).ToArray(),\r\n            new[] {\r\n                EnumResolver.UnderlyingValue,\r\n                StandardResolver.AllowPrivateExcludeNullSnakeCase,\r\n            }\r\n        );\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The static constructor gets called during compile time to setup the serializer. \r\n    ///     This variant allows custom resolvers to be passed in as well.\r\n    /// </summary>\r\n    public ArchJsonSerializer(IJsonFormatter[] custFormatters, IJsonFormatterResolver[] custResolvers)\r\n    {\r\n        // Register all important jsonformatters \r\n        _formatterResolver = CompositeResolver.Create(\r\n            _formatters.Concat(custFormatters).ToArray(),\r\n            custResolvers.Concat(new[] {\r\n                EnumResolver.UnderlyingValue,\r\n                StandardResolver.AllowPrivateExcludeNullSnakeCase,\r\n                BuiltinResolver.Instance,\r\n                DynamicGenericResolver.Instance,\r\n            }).ToArray()\r\n        );\r\n\r\n        _singleEntityFormatterResolver = CompositeResolver.Create(\r\n            _singleEntityFormatters.Concat(custFormatters).ToArray(),\r\n            custResolvers.Concat(new[] {\r\n                EnumResolver.UnderlyingValue,\r\n                StandardResolver.AllowPrivateExcludeNullSnakeCase,\r\n            }).ToArray()\r\n        );\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Serializes the given <see cref=\"World\"/> to a json-string.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> to serialize.</param>\r\n    /// <returns>Its json-string.</returns>\r\n    public string ToJson(World world)\r\n    {\r\n        return JsonSerializer.ToJsonString(world, _formatterResolver);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Serializes the given <see cref=\"Entity\"/> to a json-string.\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> the entity belongs to..</param>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <returns>Its json-string.</returns>\r\n    /// <returns>A json-string of the entity with all its components.</returns>\r\n    public string ToJson(World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return JsonSerializer.ToJsonString(entity, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Deserializes the given json <see cref=\"string\"/> to a <see cref=\"World\"/>.\r\n    /// </summary>\r\n    /// <param name=\"jsonWorld\">The json <see cref=\"string\"/> to deserialize.</param>\r\n    /// <returns>A new <see cref=\"World\"/>.</returns>\r\n    public World FromJson(string jsonWorld)\r\n    {\r\n        return JsonSerializer.Deserialize<World>(jsonWorld, _formatterResolver);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Deserializes the given json <see cref=\"string\"/> to a <see cref=\"World\"/>.\r\n    ///     <remarks>The deserialized <see cref=\"Entity\"/> will receive a new id and a new worldId.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/> to deserialize the entity into.</param>\r\n    /// <param name=\"jsonEntity\">The json <see cref=\"string\"/> of the entity to deserialize.</param>\r\n    /// <returns>A new <see cref=\"Entity\"/>.</returns>\r\n    public Entity FromJson(World world, string jsonEntity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return JsonSerializer.Deserialize<Entity>(jsonEntity, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public byte[] Serialize(World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return JsonSerializer.Serialize(entity, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(Stream stream, World world, Entity entity)\r\n    {\r\n        (_singleEntityFormatters[1] as SingleEntityFormatter)!.EntityWorld = world;\r\n        JsonSerializer.Serialize(stream, entity, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(IBufferWriter<byte> writer, World world, Entity entity)\r\n    {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public Entity Deserialize(World world, byte[] entity)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return JsonSerializer.Deserialize<Entity>(entity, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public Entity Deserialize(Stream stream, World world)\r\n    {\r\n        (_singleEntityFormatters[2] as SingleEntityFormatter)!.EntityWorld = world;\r\n        return JsonSerializer.Deserialize<Entity>(stream, _singleEntityFormatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public byte[] Serialize(World world)\r\n    {\r\n        return JsonSerializer.Serialize(world, _formatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(Stream stream, World world)\r\n    {\r\n        JsonSerializer.Serialize(stream, world, _formatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public void Serialize(IBufferWriter<byte> writer, World world)\r\n    {\r\n        throw new NotImplementedException();\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public World Deserialize(byte[] world)\r\n    {\r\n        return JsonSerializer.Deserialize<World>(world, _formatterResolver);\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    public World Deserialize(Stream stream)\r\n    {\r\n        return JsonSerializer.Deserialize<World>(stream, _formatterResolver);\r\n    }\r\n}"
  },
  {
    "path": "Arch.Persistence/StreamBufferWriter.cs",
    "content": "﻿using System.Buffers;\r\n\r\nnamespace Arch.Persistence;\r\n\r\n/// <summary>\r\n///     The <see cref=\"StreamBufferWriter\"/> class\r\n///     is a small wrapper around a <see cref=\"Stream\"/> implementing a <see cref=\"IBufferWriter{T}\"/>.\r\n///     It buffers incoming bytes in an internally stored array and flushes it regulary into the <see cref=\"_destination\"/>-<see cref=\"Stream\"/>.\r\n/// </summary>\r\npublic sealed class StreamBufferWriter : IBufferWriter<byte>, IDisposable\r\n{\r\n    /// <summary>\r\n    ///     The buffer.\r\n    /// </summary>\r\n    private byte[] _buffer;\r\n    \r\n    /// <summary>\r\n    ///     The <see cref=\"Stream\"/>.\r\n    /// </summary>\r\n    private readonly Stream _destination;\r\n    \r\n    /// <summary>\r\n    ///     If this instance owns the <see cref=\"_destination\"/> stream.\r\n    /// </summary>\r\n    private readonly bool _ownsStream;\r\n    \r\n    /// <summary>\r\n    ///     The current position and the amount of total leased bytes. \r\n    /// </summary>\r\n    private int _position, _leased;\r\n    \r\n    /// <summary>\r\n    ///     Creates a new <see cref=\"StreamBufferWriter\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"destination\">The <see cref=\"Stream\"/>.</param>\r\n    /// <param name=\"bufferSize\">The buffer-size of the <see cref=\"_buffer\"/>.</param>\r\n    /// <param name=\"ownsStream\">If it owns the stream.</param>\r\n    public StreamBufferWriter(Stream destination, int bufferSize = 1024, bool ownsStream = true)\r\n    {\r\n        const int minBufferSize = 128;\r\n        if (bufferSize < minBufferSize)\r\n        {\r\n            bufferSize = minBufferSize;\r\n        }\r\n        \r\n        _buffer = ArrayPool<byte>.Shared.Rent(bufferSize);\r\n        _ownsStream = ownsStream;\r\n        _destination = destination;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Leases an amount of bytes from the <see cref=\"_buffer\"/>.\r\n    /// </summary>\r\n    /// <param name=\"sizeHint\">The total amount.</param>\r\n    /// <returns>The leased amount.</returns>\r\n    private int Lease(int sizeHint)\r\n    {\r\n        var available = _buffer.Length - _position;\r\n        if (available < sizeHint && _position != 0)\r\n        {   // try to get more\r\n            Flush();\r\n            available = _buffer.Length - _position;\r\n        }\r\n\r\n        _leased = available;\r\n        return available;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Flushes the buffered bytes to the <see cref=\"_destination\"/>.\r\n    /// </summary>\r\n    /// <param name=\"flushUnderlyingStream\">If it also should flush the <see cref=\"Stream\"/>.</param>\r\n    public void Flush(bool flushUnderlyingStream = false)\r\n    {\r\n        if (_position != 0)\r\n        {\r\n            _destination.Write(_buffer, 0, _position);\r\n            _position = 0;\r\n        }\r\n        if (flushUnderlyingStream)\r\n        {\r\n            _destination.Flush();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Advances the buffer, notifies this instance that there was something new written into the <see cref=\"_buffer\"/> memory. \r\n    /// </summary>\r\n    /// <param name=\"count\">The amount of bytes written.</param>\r\n    /// <exception cref=\"ArgumentOutOfRangeException\">Throws if we are out of memory.</exception>\r\n    void IBufferWriter<byte>.Advance(int count)\r\n    {\r\n        if (count > _leased || count < 0) throw new ArgumentOutOfRangeException(nameof(count));\r\n        _position += count;\r\n        _leased = 0;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a partion of the <see cref=\"_buffer\"/> as a <see cref=\"Memory{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"sizeHint\">The total amount.</param>\r\n    /// <returns>The new <see cref=\"Memory{T}\"/> instance.</returns>\r\n    Memory<byte> IBufferWriter<byte>.GetMemory(int sizeHint)\r\n    {\r\n        var actual = Lease(sizeHint);\r\n        return new Memory<byte>(_buffer, _position, actual);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns a partion of the <see cref=\"_buffer\"/> as a <see cref=\"Span{T}\"/>.\r\n    /// </summary>\r\n    /// <param name=\"sizeHint\">The total amount.</param>\r\n    /// <returns>The new <see cref=\"Span{T}\"/> instance.</returns>\r\n    Span<byte> IBufferWriter<byte>.GetSpan(int sizeHint)\r\n    {\r\n        var actual = Lease(sizeHint);\r\n        return new Span<byte>(_buffer, _position, actual);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Disposes this instance, flushes and releases all memory. \r\n    /// </summary>\r\n    public void Dispose()\r\n    {\r\n        Flush(true);\r\n        \r\n        var tmp = _buffer;\r\n        _buffer = null!;\r\n        ArrayPool<byte>.Shared.Return(tmp);\r\n\r\n        if (_ownsStream)\r\n        {\r\n            _destination.Dispose();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.Persistence.Tests/Arch.Persistence.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFramework>net7.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n\r\n        <IsPackable>false</IsPackable>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.2.0\"/>\r\n        <PackageReference Include=\"NUnit\" Version=\"3.13.3\"/>\r\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.2.1\"/>\r\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"3.3.0\"/>\r\n        <PackageReference Include=\"coverlet.collector\" Version=\"3.1.2\"/>\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n      <ProjectReference Include=\"..\\Arch.Persistence\\Arch.Persistence.csproj\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.Persistence.Tests/PersistenceTest.cs",
    "content": "using Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing CommunityToolkit.HighPerformance;\r\nusing static NUnit.Framework.Assert;\r\nusing Throws = NUnit.Framework.Throws;\r\n\r\nnamespace Arch.Persistence.Tests;\r\n\r\n/// <summary>\r\n///     The <see cref=\"Transform\"/> struct\r\n///     represents a test component that is being (de)serialized.\r\n/// </summary>\r\npublic record struct Transform\r\n{\r\n    public float X;\r\n    public float Y;\r\n}\r\n\r\n/// <summary>\r\n///     The <see cref=\"MetaData\"/> struct\r\n///     represents a test component that is being (de)serialized.\r\n/// </summary>\r\npublic record struct MetaData\r\n{\r\n    public string Name;\r\n}\r\n\r\npublic class Tests\r\n{\r\n\r\n    private ArchBinarySerializer _binarySerializer;\r\n    private ArchJsonSerializer _jsonSerializer;\r\n    private World _world;\r\n    \r\n    [SetUp]\r\n    public void Setup()\r\n    {\r\n        _binarySerializer = new ArchBinarySerializer();\r\n        _jsonSerializer = new ArchJsonSerializer();\r\n        \r\n        _world = World.Create();\r\n        for (var index = 0; index < 1000; index++)\r\n        {\r\n            _world.Create(new Transform { X = index, Y = index }, new MetaData{ Name = index.ToString()});\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if a world is being serialized and deserialized correctly using the <see cref=\"_binarySerializer\"/>.\r\n    /// </summary>\r\n    [Test]\r\n    public void BinaryWorldSerialization()\r\n    {\r\n        var bytes = _binarySerializer.Serialize(_world);\r\n        var newWorld = _binarySerializer.Deserialize(bytes);\r\n        \r\n        // Equal in structure?\r\n        That(newWorld.Capacity, Is.EqualTo(_world.Capacity));\r\n        That(newWorld.Size, Is.EqualTo(_world.Size));\r\n        That(newWorld.Archetypes.Count, Is.EqualTo(_world.Archetypes.Count));\r\n\r\n        // Are archetypes equal?\r\n        for (var index = 0; index < _world.Archetypes.Count; index++)\r\n        {\r\n            var archetype = _world.Archetypes[index];\r\n            var newArchetype = newWorld.Archetypes[index];\r\n            \r\n            That(archetype.ChunkCapacity, Is.EqualTo(newArchetype.ChunkCapacity));\r\n            That(archetype.EntityCount, Is.EqualTo(newArchetype.EntityCount));\r\n        }\r\n        \r\n        // Are entities equal?\r\n        var entities = new Entity[_world.Size];\r\n        _world.GetEntities(new QueryDescription().WithNone<int>(), entities.AsSpan());\r\n        \r\n        var newEntities = new Entity[newWorld.Size];\r\n        newWorld.GetEntities(new QueryDescription(), newEntities.AsSpan());\r\n\r\n        for (var index = 0; index < entities.Length; index++)\r\n        {\r\n            var entity = entities[index];\r\n            var newEntity = newEntities[index];\r\n            \r\n            That(entity.Id, Is.EqualTo(newEntity.Id));\r\n            That(entity.Version, Is.EqualTo(newEntity.Version));\r\n            That(entity.Get<Transform>(), Is.EqualTo(newEntity.Get<Transform>()));\r\n            That(entity.Get<MetaData>(), Is.EqualTo(newEntity.Get<MetaData>()));\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if an entity is being serialized and deserialized correctly using the <see cref=\"_binarySerializer\"/>.\r\n    /// </summary>\r\n    [Test]\r\n    public void BinaryEntitySerialization()\r\n    {\r\n        var entity = _world.Archetypes[0].GetChunk(0).Entity(0);\r\n        var bytes = _binarySerializer.Serialize(_world, entity);\r\n\r\n        var newWorld = World.Create();\r\n        var newEntity = _binarySerializer.Deserialize(newWorld, bytes);\r\n        \r\n        That(newEntity.Get<Transform>(), Is.EqualTo(entity.Get<Transform>()));\r\n        That(newEntity.Get<MetaData>(), Is.EqualTo(entity.Get<MetaData>()));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if a world is being serialized and deserialized correctly using the <see cref=\"_jsonSerializer\"/>.\r\n    /// </summary>\r\n    [Test]\r\n    public void JsonWorldSerialization()\r\n    {\r\n        var bytes = _jsonSerializer.Serialize(_world);\r\n        var newWorld = _jsonSerializer.Deserialize(bytes);\r\n        \r\n        // Equal in structure?\r\n        That(newWorld.Capacity, Is.EqualTo(_world.Capacity));\r\n        That(newWorld.Size, Is.EqualTo(_world.Size));\r\n        That(newWorld.Archetypes.Count, Is.EqualTo(_world.Archetypes.Count));\r\n\r\n        // Are archetypes equal?\r\n        for (var index = 0; index < _world.Archetypes.Count; index++)\r\n        {\r\n            var archetype = _world.Archetypes[index];\r\n            var newArchetype = newWorld.Archetypes[index];\r\n            \r\n            That(archetype.ChunkCapacity, Is.EqualTo(newArchetype.ChunkCapacity));\r\n            That(archetype.EntityCount, Is.EqualTo(newArchetype.EntityCount));\r\n        }\r\n        \r\n        // Are entities equal?\r\n        var entities = new Entity[_world.Size];\r\n        _world.GetEntities(new QueryDescription().WithNone<int>(), entities.AsSpan());\r\n        \r\n        var newEntities = new Entity[newWorld.Size];\r\n        newWorld.GetEntities(new QueryDescription(), newEntities.AsSpan());\r\n\r\n        for (var index = 0; index < entities.Length; index++)\r\n        {\r\n            var entity = entities[index];\r\n            var newEntity = newEntities[index];\r\n            \r\n            That(entity.Id, Is.EqualTo(newEntity.Id));\r\n            That(entity.Get<Transform>(), Is.EqualTo(newEntity.Get<Transform>()));\r\n            That(entity.Get<MetaData>(), Is.EqualTo(newEntity.Get<MetaData>()));\r\n        }\r\n    }\r\n    \r\n    \r\n    /// <summary>\r\n    ///     Checks if an entity is being serialized and deserialized correctly using the <see cref=\"_binarySerializer\"/>.\r\n    /// </summary>\r\n    [Test]\r\n    public void JsonEntitySerialization()\r\n    {\r\n        var entity = _world.Archetypes[0].GetChunk(0).Entity(0);\r\n        var bytes = _jsonSerializer.Serialize(_world, entity);\r\n\r\n        var newWorld = World.Create();\r\n        var newEntity = _jsonSerializer.Deserialize(newWorld, bytes);\r\n        \r\n        That(newEntity.Get<Transform>(), Is.EqualTo(entity.Get<Transform>()));\r\n        That(newEntity.Get<MetaData>(), Is.EqualTo(entity.Get<MetaData>()));\r\n    }\r\n}"
  },
  {
    "path": "Arch.Persistence.Tests/Usings.cs",
    "content": "global using NUnit.Framework;"
  },
  {
    "path": "Arch.Relationships/Arch.Relationships.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <TargetFrameworks>net7.0;net6.0;netstandard2.1</TargetFrameworks>\r\n        <LangVersion>11</LangVersion>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <Title>Arch.Relationships</Title>\r\n        <Description>Simple Entity-Relationships for Arch.</Description>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n        <PackageReleaseNotes>Relationships now use less memory and are serializable.</PackageReleaseNotes>\r\n        <Authors>genaray</Authors>\r\n        <Version>2.1.0</Version>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n\r\n        <UnityPublish>true</UnityPublish>\r\n    </PropertyGroup>\r\n\r\n    <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\r\n      <DefineConstants>TRACE;EVENTS</DefineConstants>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n      <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.Relationships/EntityRelationshipExtensions.cs",
    "content": "﻿using System.Diagnostics.Contracts;\r\nusing System.Runtime.CompilerServices;\r\nusing Arch.Core;\r\n\r\nnamespace Arch.Relationships;\r\n\r\n#if !PURE_ECS\r\n\r\n/// <summary>\r\n///     The <see cref=\"EntityRelationshipExtensions\"/> class\r\n///     stores several methods to forward relationship methods from the <see cref=\"World\"/> to the <see cref=\"Entity\"/>.\r\n/// </summary>\r\npublic static class EntityRelationshipExtensions\r\n{\r\n\r\n    /// <summary>\r\n    ///     Adds a new relationship to the <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"relationship\">The relationship instance.</param>\r\n    public static void AddRelationship<T>(this in Entity source, Entity target, T relationship = default!)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        world.AddRelationship(source, target, relationship);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Sets a relationship to the <see cref=\"Entity\"/> by updating its relationship data.\r\n    /// </summary>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"relationship\">The relationship instance.</param>\r\n    public static void SetRelationship<T>(this in Entity source, Entity target, T relationship = default!)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        world.SetRelationship(source, target, relationship);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if an <see cref=\"Entity\"/> has a certain relationship.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>True if it has the desired relationship, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool HasRelationship<T>(this in Entity source, Entity target)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        return world.HasRelationship<T>(source, target);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if an <see cref=\"Entity\"/> has a certain relationship.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>True if it has the desired relationship, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool HasRelationship<T>(this in Entity source)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        return world.HasRelationship<T>(source);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a relationship of an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>The relationship.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static T GetRelationship<T>(this in Entity source, Entity target)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        return world.GetRelationship<T>(source, target);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a relationship of an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>The <see cref=\"Relationship{T}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static ref Relationship<T> GetRelationships<T>(this in Entity source)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        return ref world.GetRelationships<T>(source);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Tries to return an <see cref=\"Entity\"/>s relationship of the specified type.\r\n    ///     Will copy the relationship if its a struct.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"relationship\">The found relationship.</param>\r\n    /// <returns>True if it exists, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool TryGetRelationship<T>(this in Entity source, Entity target, out T relationship)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        return world.TryGetRelationship(source, target, out relationship);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Removes a relationship from an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"source\">The <see cref=\"Entity\"/> to remove the relationship from.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    public static void RemoveRelationship<T>(this in Entity source, Entity target)\r\n    {\r\n        var world = World.Worlds[source.WorldId];\r\n        world.RemoveRelationship<T>(source, target);\r\n    }\r\n}\r\n\r\n#endif\r\n"
  },
  {
    "path": "Arch.Relationships/Enumerators.cs",
    "content": "using System.Collections;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions.Dangerous;\r\nusing CommunityToolkit.HighPerformance;\r\n\r\nnamespace Arch.Relationships;\r\n\r\n/// <summary>\r\n///     The <see cref=\"SortedListEnumerator{TValue}\"/> struct\r\n///     is a enumerator to enumerate a passed <see cref=\"SortedList{TKey,TValue}\"/> in an efficient way. \r\n/// </summary>\r\n/// <typeparam name=\"TValue\"></typeparam>\r\npublic struct SortedListEnumerator<TValue> \r\n{\r\n    private SortedList<Entity, TValue> sortedList;\r\n    private int currentIndex;\r\n\r\n    /// <summary>\r\n    /// Constructor.\r\n    /// </summary>\r\n    /// <param name=\"list\">List.</param>\r\n    public SortedListEnumerator(SortedList<Entity, TValue> list)\r\n    {\r\n        sortedList = list;\r\n        currentIndex = -1;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Current.\r\n    /// </summary>\r\n    public KeyValuePair<Entity, TValue> Current\r\n    {\r\n        get\r\n        {\r\n            if (currentIndex == -1 || currentIndex >= sortedList.Count)\r\n                throw new InvalidOperationException();\r\n                \r\n            var key = sortedList.Keys[currentIndex];\r\n            var value = sortedList.Values[currentIndex];\r\n            return new KeyValuePair<Entity, TValue>(key, value);\r\n        }\r\n    }\r\n    \r\n    /// <summary>\r\n    /// Moves to the next element in the enumerator.\r\n    /// </summary>\r\n    public bool MoveNext()\r\n    {\r\n        currentIndex++;\r\n        return currentIndex < sortedList.Count;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Resets the enumerator to its initial position.\r\n    /// </summary>\r\n    public void Reset()\r\n    {\r\n        currentIndex = -1;\r\n    }\r\n}"
  },
  {
    "path": "Arch.Relationships/InRelationship.cs",
    "content": "﻿using Arch.Core;\r\nusing Arch.Core.Utils;\r\n\r\nnamespace Arch.Relationships;\r\n\r\n\r\n/// <summary>\r\n///     The struct <see cref=\"InRelationship\"/>\r\n///     represents a reference to a <see cref=\"Relationship{T}\"/>.\r\n///     It sits on an <see cref=\"Entity\"/> to indicate in which other <see cref=\"Relationship{T}\"/>s it is involved in.\r\n/// </summary>\r\ninternal readonly struct InRelationship\r\n{\r\n    /// <summary>\r\n    ///     The id of the <see cref=\"Relationship{T}\"/>-Component that this <see cref=\"InRelationship\"/> points to.\r\n    ///     Basically the <see cref=\"Relationship{T}\"/> the <see cref=\"Entity\"/> is in.\r\n    ///     TODO: Uhmm... how the heck do we convert the Id back to the <see cref=\"ComponentType\"/>?\r\n    /// </summary>\r\n    public readonly int ComponentTypeId;\r\n\r\n    /// <summary>\r\n    ///     Creates a new <see cref=\"InRelationship\"/> instance.\r\n    /// </summary>\r\n    /// <param name=\"targetRelation\">The <see cref=\"ComponentType\"/> that represents the relation.</param>\r\n    internal InRelationship(ComponentType targetRelation)\r\n    {\r\n        ComponentTypeId = targetRelation.Id;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a new <see cref=\"InRelationship\"/> instance.\r\n    /// <remarks>Mostly for binary serialization.</remarks>\r\n    /// </summary>\r\n    /// <param name=\"componentTypeId\">The <see cref=\"ComponentTypeId\"/>.</param>\r\n    internal InRelationship(int componentTypeId)\r\n    {\r\n        ComponentTypeId = componentTypeId;\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.Relationships/Relationship.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing Arch.Core;\r\n\r\nnamespace Arch.Relationships;\r\n\r\n/// <summary>\r\n///     The <see cref=\"IRelationship\"/> interface\r\n///     is an interface that provides all methods required to act as a relationship.\r\n/// </summary>\r\ninternal interface IRelationship\r\n{\r\n    /// <summary>\r\n    ///     The amount of relationships currently in the buffer.\r\n    /// </summary>\r\n    int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes the buffer as a component from the given world and entity.\r\n    /// </summary>\r\n    /// <param name=\"world\"></param>\r\n    /// <param name=\"source\"></param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void Destroy(World world, Entity source);\r\n\r\n    /// <summary>\r\n    ///     Removes the relationship targeting <paramref name=\"target\"/> from this buffer.\r\n    /// </summary>\r\n    /// <param name=\"target\">The <see cref=\"Entity\"/> in the relationship to remove.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    void Remove(Entity target);\r\n}\r\n\r\n/// <summary>\r\n///     A buffer storing relationships of <see cref=\"Entity\"/> and <typeparamref name=\"T\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The type of the second relationship element.</typeparam>\r\npublic class Relationship<T> : IRelationship\r\n{\r\n\r\n    /// <summary>\r\n    ///     Its relations. \r\n    /// </summary>\r\n    internal readonly SortedList<Entity, T> Elements;\r\n\r\n    /// <summary>\r\n    ///     Initializes a new instance of an <see cref=\"Relationship{T}\"/>.\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal Relationship()\r\n    {\r\n        Elements = new SortedList<Entity, T>();\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Initializes a new instance of an <see cref=\"Relationship{T}\"/>.\r\n    /// <remarks>Mostly for binary serialization.</remarks>\r\n    /// </summary>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal Relationship(SortedList<Entity, T> elements)\r\n    {\r\n        Elements = elements;\r\n    }\r\n    \r\n    /// <inheritdoc/>\r\n    int IRelationship.Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => Elements.Count;\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IRelationship.Count\"/>\r\n    internal int Count\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        get => ((IRelationship) this).Count;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds a relationship to this buffer.\r\n    /// </summary>\r\n    /// <param name=\"relationship\">The instance of the relationship.</param>\r\n    /// <param name=\"target\">The target of the relationship.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void Add(in T relationship, Entity target)\r\n    {\r\n        Elements.Add(target, relationship);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Sets the stored <typeparamref name=\"T\"/> for the given <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <param name=\"data\">The data to store.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public void Set(Entity entity, T data = default!)\r\n    {\r\n        Elements[entity] = data;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Determines whether the given <see cref=\"Relationship{T}\"/> contains the passed <see cref=\"Entity\"/> or not.\r\n    /// </summary>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <returns>True or false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool Contains(Entity entity)\r\n    {\r\n        return Elements.ContainsKey(entity);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns the stored <typeparamref name=\"T\"/> for the given <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <returns>The stored <typeparamref name=\"T\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public T Get(Entity entity)\r\n    {\r\n        return Elements[entity];\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns the stored <typeparamref name=\"T\"/> for the given <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"entity\">The <see cref=\"Entity\"/>.</param>\r\n    /// <param name=\"value\">The stored <typeparamref name=\"T\"/>.</param>\r\n    /// <returns>The stored <typeparamref name=\"T\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public bool TryGetValue(Entity entity, out T value)\r\n    {\r\n        return Elements.TryGetValue(entity, out value!);\r\n    }\r\n    \r\n    /// <inheritdoc/>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    void IRelationship.Remove(Entity target)\r\n    {\r\n        Elements.Remove(target);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IRelationship.Remove(Entity)\"/>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void Remove(Entity target)\r\n    {\r\n        ((IRelationship) this).Remove(target);\r\n    }\r\n    \r\n    /// <inheritdoc/>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    void IRelationship.Destroy(World world, Entity source)\r\n    {\r\n        world.Remove<Relationship<T>>(source);\r\n    }\r\n\r\n    /// <inheritdoc cref=\"IRelationship.Destroy(World, Entity)\"/>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal void Destroy(World world, Entity source)\r\n    {\r\n        ((IRelationship) this).Destroy(world, source);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates a new <see cref=\"SortedListEnumerator{TValue}\"/>.\r\n    /// </summary>\r\n    /// <returns>The new <see cref=\"SortedListEnumerator{TValue}\"/>.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public SortedListEnumerator<T> GetEnumerator()\r\n    {\r\n        return new SortedListEnumerator<T>(Elements);\r\n    }\r\n};\r\n"
  },
  {
    "path": "Arch.Relationships/WorldRelationshipExtensions.cs",
    "content": "﻿using System.Diagnostics.Contracts;\r\nusing System.Runtime.CompilerServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Extensions.Dangerous;\r\nusing Arch.Core.Utils;\r\n\r\n[assembly:InternalsVisibleTo(\"Arch.Relationships.Tests\")]\r\nnamespace Arch.Relationships;\r\n\r\n/// <summary>\r\n///     The <see cref=\"WorldRelationshipExtensions\"/> class\r\n///     stores several extension methods for relationships handling. \r\n/// </summary>\r\npublic static class WorldRelationshipExtensions\r\n{\r\n    \r\n#if EVENTS\r\n    \r\n    /// <summary>\r\n    ///     Subscribes to entity destruction events to cleanup their relations. \r\n    /// </summary>\r\n    public static void HandleRelationshipCleanup(this World world)\r\n    {\r\n        world.SubscribeEntityDestroyed((in Entity entity) => CleanupRelationships(world, in entity));\r\n    }\r\n\r\n    // TODO: Probably someone will kill me for the dark magic that happens down below. \r\n    /// <summary>\r\n    ///     Cleans up all relations of the passed <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"world\"></param>\r\n    /// <param name=\"entity\"></param>\r\n    public static void CleanupRelationships(this World world, in Entity entity)\r\n    {\r\n        ref var relationships = ref world.TryGetRefRelationships<InRelationship>(entity, out var exists);\r\n        if (!exists)\r\n        {\r\n            return;\r\n        }\r\n        \r\n        foreach (var (target, inRelationship) in relationships.Elements)\r\n        {\r\n            var id = inRelationship.ComponentTypeId;\r\n            var componentType = new ComponentType(id, 0);\r\n            \r\n            // Get slots, chunk and array to prevent entity.Get(type) object allocation\r\n            ref readonly var chunk = ref world.GetChunk(target);\r\n            var array = chunk.GetArray(componentType);\r\n            var relationshipsArray = Unsafe.As<IRelationship[]>(array);\r\n\r\n            var slot = world.GetSlot(target);\r\n            var relationship = relationshipsArray[slot.Index];\r\n            relationship.Remove(entity);\r\n            \r\n            if (relationship.Count == 0)\r\n            {\r\n                relationship.Destroy(world, target);\r\n            }\r\n\r\n            ref var targetRelationships = ref world.TryGetRefRelationships<InRelationship>(target, out exists);\r\n            if (!exists)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            targetRelationships.Remove(entity);\r\n        }\r\n    }\r\n#endif\r\n\r\n    /// <summary>\r\n    ///     Adds a new relationship to the <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"relationship\">The relationship instance.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void AddRelationship<T>(this World world, Entity source, Entity target, in T relationship = default!)\r\n    {\r\n        ref var buffer = ref world.AddOrGetRelationships<T>(source);\r\n        buffer.Add(in relationship, target);\r\n\r\n        var targetComp = new InRelationship(Component<Relationship<T>>.ComponentType);\r\n        ref var targetBuffer = ref world.AddOrGetRelationships<InRelationship>(target);\r\n        targetBuffer.Add(in targetComp, source);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the existence of a relationship on an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"relationship\">The relationship value used if its being added.</param>\r\n    /// <returns>The relationship.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static T AddOrGetRelationship<T>(this World world, Entity source, Entity target, in T relationship = default!)\r\n    {\r\n        ref var relationships = ref world.TryGetRefRelationships<T>(source, out var exists);\r\n        if (exists)\r\n        {\r\n            return relationships.Get(target);\r\n        }\r\n\r\n        world.AddRelationship(source, target, in relationship);\r\n        return world.GetRelationship<T>(source, target);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Ensures the existence of a buffer of relationships on an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationships.</param>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <returns>The relationships.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    internal static ref Relationship<T> AddOrGetRelationships<T>(this World world, Entity source)\r\n    {\r\n        ref var component = ref world.TryGetRef<Relationship<T>>(source, out var exists);\r\n        if (exists)\r\n        {\r\n            return ref component!;\r\n        }\r\n\r\n        world.Add(source, new Relationship<T>());\r\n        return ref world.Get<Relationship<T>>(source);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Sets the existing relationship data.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"relationship\">The new data.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void SetRelationship<T>(this World world, Entity source, Entity target, in T relationship = default!)\r\n    {\r\n        ref var relationships = ref world.GetRelationships<T>(source);\r\n        relationships.Set(target, relationship);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if an <see cref=\"Entity\"/> has a certain relationship.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>True if it has the desired relationship, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool HasRelationship<T>(this World world, Entity source, Entity target)\r\n    {\r\n        ref var relationships = ref world.TryGetRefRelationships<T>(source, out var exists);\r\n        if (!exists)\r\n        {\r\n            return false;\r\n        }\r\n\r\n        return relationships.Contains(target);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if an <see cref=\"Entity\"/> has a certain relationship.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>True if it has the desired relationship, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool HasRelationship<T>(this World world, Entity source)\r\n    {\r\n        return world.Has<Relationship<T>>(source);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns a relationship of an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>The relationship.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static T GetRelationship<T>(this World world, Entity source, Entity target)\r\n    {\r\n        ref var relationships = ref world.GetRelationships<T>(source);\r\n        return relationships.Get(target);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Tries to return an <see cref=\"Entity\"/>s relationship of the specified type.\r\n    ///     Will copy the relationship if its a struct.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <param name=\"relationship\">The found relationship.</param>\r\n    /// <returns>True if it exists, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static bool TryGetRelationship<T>(this World world, Entity source, Entity target, out T relationship)\r\n    {\r\n        ref var relationships = ref world.TryGetRefRelationships<T>(source, out var exists);\r\n        if (!exists)\r\n        {\r\n            relationship = default!;\r\n            return false;\r\n        }\r\n\r\n        return relationships.TryGetValue(target, out relationship);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Returns all relationships of the given type of an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The source <see cref=\"Entity\"/> of the relationship.</param>\r\n    /// <returns>A reference to the relationships.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    public static ref Relationship<T> GetRelationships<T>(this World world, Entity source)\r\n    {\r\n        return ref world.Get<Relationship<T>>(source);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Tries to return an <see cref=\"Entity\"/>s relationships of the specified type.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The <see cref=\"Entity\"/>.</param>\r\n    /// <param name=\"relationships\">The found relationships.</param>\r\n    /// <returns>True if it exists, otherwise false.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    internal static bool TryGetRelationships<T>(this World world, Entity source, out Relationship<T> relationships)\r\n    {\r\n        return world.TryGet(source, out relationships!);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Tries to return a reference to an <see cref=\"Entity\"/>s relationships of the\r\n    ///     specified type.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The <see cref=\"Entity\"/>.</param>\r\n    /// <param name=\"exists\">True if it exists, otherwise false.</param>\r\n    /// <returns>A reference to the relationships.</returns>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]\r\n    internal static ref Relationship<T> TryGetRefRelationships<T>(this World world, Entity source, out bool exists)\r\n    {\r\n        return ref world.TryGetRef<Relationship<T>>(source, out exists);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Removes a relationship from an <see cref=\"Entity\"/>.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">The relationship type.</typeparam>\r\n    /// <param name=\"world\">World.</param>\r\n    /// <param name=\"source\">The <see cref=\"Entity\"/> to remove the relationship from.</param>\r\n    /// <param name=\"target\">The target <see cref=\"Entity\"/> of the relationship.</param>\r\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n    public static void RemoveRelationship<T>(this World world, Entity source, Entity target)\r\n    {\r\n        ref var buffer = ref world.GetRelationships<T>(source);\r\n        buffer.Remove(target);\r\n\r\n        if (buffer.Count == 0)\r\n        {\r\n            world.Remove<Relationship<T>>(source);\r\n        }\r\n\r\n        ref var targetBuffer = ref world.GetRelationships<InRelationship>(target);\r\n        targetBuffer.Remove(source);\r\n\r\n        if (targetBuffer.Count == 0)\r\n        {\r\n            world.Remove<Relationship<InRelationship>>(target);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.Relationships.Tests/Arch.Relationships.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFramework>net7.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n\r\n        <IsPackable>false</IsPackable>\r\n\r\n        <RootNamespace>Arch.Relationships.Tests</RootNamespace>\r\n    </PropertyGroup>\r\n\r\n    <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\r\n      <DefineConstants>TRACE;</DefineConstants>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.2.0\" />\r\n        <PackageReference Include=\"NUnit\" Version=\"3.13.3\" />\r\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.2.1\" />\r\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"3.3.0\" />\r\n        <PackageReference Include=\"coverlet.collector\" Version=\"3.1.2\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n      <ProjectReference Include=\"..\\Arch.Relationships\\Arch.Relationships.csproj\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.Relationships.Tests/RelationshipTest.cs",
    "content": "using System.Runtime.CompilerServices;\r\nusing Arch.Core;\r\nusing static NUnit.Framework.Assert;\r\nusing Throws = NUnit.Framework.Throws;\r\n\r\nnamespace Arch.Relationships.Tests;\r\n\r\n//#if EVENTS\r\n\r\npublic record struct ParentOf;\r\npublic record struct ChildOf;\r\n\r\n/// <summary>\r\n///     The <see cref=\"RelationshipTest\"/> class\r\n///     contains several tests to check if the relations work correctly. \r\n/// </summary>\r\n[TestFixture]\r\npublic class RelationshipTest\r\n{\r\n    private World _world = default!;\r\n\r\n    [SetUp]\r\n    public void SetUp()\r\n    {\r\n        _world = World.Create();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if no relationships are handled corretly. \r\n    /// </summary>\r\n    [Test]\r\n    public void NoRelationships()\r\n    {\r\n        // Create entities without setting any relationships\r\n        var parent = _world.Create();\r\n        var childOne = _world.Create();\r\n        var childTwo = _world.Create();\r\n\r\n        // Get should throw\r\n        That(() => _world.GetRelationships<ParentOf>(parent), Throws.Exception);\r\n        That(() => _world.GetRelationships<ChildOf>(childOne), Throws.Exception);\r\n        That(() => _world.GetRelationships<ChildOf>(childTwo), Throws.Exception);\r\n\r\n        // TryGet should return false\r\n        False(_world.TryGetRelationships<ParentOf>(parent, out _));\r\n        False(_world.TryGetRelationships<ChildOf>(childOne, out _));\r\n        False(_world.TryGetRelationships<ChildOf>(childTwo, out _));\r\n\r\n        // TryGetRef should return a null ref and false\r\n        That(Unsafe.IsNullRef(ref _world.TryGetRefRelationships<ParentOf>(parent, out var exists)));\r\n        False(exists);\r\n\r\n        That(Unsafe.IsNullRef(ref _world.TryGetRefRelationships<ChildOf>(childOne, out exists)));\r\n        False(exists);\r\n\r\n        That(Unsafe.IsNullRef(ref _world.TryGetRefRelationships<ChildOf>(childTwo, out exists)));\r\n        False(exists);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Checks if relationships were added correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void AddRelationship()\r\n    {\r\n        var source = _world.Create();\r\n        var target = _world.Create();\r\n        \r\n        source.AddRelationship<ParentOf>(target);\r\n        That(source.HasRelationship<ParentOf>(), Is.True);\r\n        That(source.HasRelationship<ParentOf>(target), Is.True);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if relationships were set correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void RelationshipData()\r\n    {\r\n        var source = _world.Create();\r\n        var target = _world.Create();\r\n        var dummy = _world.Create();\r\n        \r\n        source.AddRelationship(target, 5);\r\n        source.AddRelationship(dummy, 100);\r\n        \r\n        var data = source.GetRelationship<int>(target);\r\n        That(data, Is.EqualTo(5));\r\n        \r\n        source.SetRelationship(target, 10);\r\n        data = source.GetRelationship<int>(target);\r\n        That(data, Is.EqualTo(10));\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Checks if relationships were removed correctly.\r\n    /// </summary>\r\n    [Test]\r\n    public void RemoveRelationship()\r\n    {\r\n        var source = _world.Create();\r\n        var target = _world.Create();\r\n        \r\n        source.AddRelationship<ParentOf>(target);\r\n\r\n        That(source.HasRelationship<ParentOf>(), Is.True);\r\n        That(source.HasRelationship<ParentOf>(target), Is.True);\r\n        \r\n        source.RemoveRelationship<ParentOf>(target);\r\n        That(source.HasRelationship<ParentOf>(), Is.False);\r\n    }\r\n\r\n#if EVENTS\r\n\r\n    [Test]\r\n    public void RelationshipCleanup()\r\n    {\r\n        // Setup handling relationship cleanup\r\n        _world.HandleRelationshipCleanup();\r\n\r\n        // Create entities\r\n        var parent = _world.Create();\r\n        var childOne = _world.Create();\r\n        var childTwo = _world.Create();\r\n\r\n        // Add the relationships\r\n        _world.AddRelationship<ParentOf>(parent, childOne);\r\n        _world.AddRelationship<ParentOf>(parent, childTwo);\r\n        _world.AddRelationship<ChildOf>(childOne, parent);\r\n        _world.AddRelationship<ChildOf>(childTwo, parent);\r\n\r\n        // Get should return a reference to the relationships\r\n        That(_world.GetRelationships<ParentOf>(parent).Elements, Does\r\n            .ContainKey(childOne).And\r\n            .ContainKey(childTwo));\r\n        That(_world.GetRelationships<ChildOf>(childOne).Elements, Does.ContainKey(parent));\r\n        That(_world.GetRelationships<ChildOf>(childTwo).Elements, Does.ContainKey(parent));\r\n\r\n        // TryGet should return true and the relationships\r\n        True(_world.TryGetRelationships<ParentOf>(parent, out var parentRelationships));\r\n        That(parentRelationships.Elements, Does.ContainKey(childOne).And.ContainKey(childTwo));\r\n\r\n        True(_world.TryGetRelationships<ChildOf>(childOne, out var childRelationships));\r\n        That(childRelationships.Elements, Does.ContainKey(parent));\r\n\r\n        True(_world.TryGetRelationships<ChildOf>(childTwo, out childRelationships));\r\n        That(childRelationships.Elements, Does.ContainKey(parent));\r\n\r\n        // TryGetRef should return a reference to the relationships and true\r\n        ref var parentRelationshipsRef = ref _world.TryGetRefRelationships<ParentOf>(parent, out var exists);\r\n        True(exists);\r\n        That(parentRelationshipsRef.Elements, Does.ContainKey(childOne).And.ContainKey(childTwo));\r\n\r\n        ref var childOneRelationshipsRef = ref _world.TryGetRefRelationships<ChildOf>(childOne, out exists);\r\n        True(exists);\r\n        That(childOneRelationshipsRef.Elements, Does.ContainKey(parent));\r\n\r\n        ref var childTwoRelationshipsRef = ref _world.TryGetRefRelationships<ChildOf>(childTwo, out exists);\r\n        True(exists);\r\n        That(childTwoRelationshipsRef.Elements, Does.ContainKey(parent));\r\n\r\n        // Destroy childOne, should remove any relationships containing it\r\n        _world.CleanupRelationships(childOne);\r\n        _world.Destroy(childOne);\r\n\r\n        // Get should throw on childOne and not return it in any of the other references\r\n        That(_world.GetRelationships<ParentOf>(parent).Elements, Does.Not.ContainKey(childOne).And.ContainKey(childTwo));\r\n        That(() => _world.GetRelationships<ChildOf>(childOne).Elements, Throws.Exception);\r\n        That(_world.GetRelationships<ChildOf>(childTwo).Elements, Does.ContainKey(parent));\r\n\r\n        // Destroy childTwo, should remove any relationships containing it\r\n        _world.Destroy(childTwo);\r\n\r\n        // Get, all should throw as no relationships are left\r\n        That(() => _world.GetRelationships<ParentOf>(parent), Throws.Exception);\r\n        That(() => _world.GetRelationships<ChildOf>(childOne), Throws.Exception);\r\n        That(() => _world.GetRelationships<ChildOf>(childTwo), Throws.Exception);\r\n\r\n        // Destroy parent\r\n        DoesNotThrow(() => _world.Destroy(parent));\r\n    }\r\n#endif\r\n\r\n    [Test]\r\n    public void QueryRelationship()\r\n    {\r\n        // Create entities\r\n        var parent = _world.Create();\r\n        var childOne = _world.Create();\r\n        var childTwo = _world.Create();\r\n\r\n        // Add relationships\r\n        _world.AddRelationship<ParentOf>(parent, childOne);\r\n        _world.AddRelationship<ParentOf>(parent, childTwo);\r\n        _world.AddRelationship<ChildOf>(childOne, parent);\r\n        _world.AddRelationship<ChildOf>(childTwo, parent);\r\n\r\n        // Query all ParentOf relationships\r\n        var query = new QueryDescription().WithAll<Relationship<ParentOf>>();\r\n        var entities = new List<Entity>();\r\n        _world.Query(query, (ref Relationship<ParentOf> parentOf) =>\r\n        {\r\n            entities.AddRange(parentOf.Elements.Select(p => p.Key));\r\n        });\r\n\r\n        // Should find two ParentOf relationships, from childOne and childTwo\r\n        That(entities, Has.Count.EqualTo(2));\r\n        That(entities, Does.Contain(childOne));\r\n        That(entities, Does.Contain(childTwo));\r\n    }\r\n}\r\n\r\n//#endif\r\n"
  },
  {
    "path": "Arch.Relationships.Tests/Usings.cs",
    "content": "global using NUnit.Framework;"
  },
  {
    "path": "Arch.System/Arch.System.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFrameworks>net7.0; net6.0; netstandard2.1</TargetFrameworks>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <PackageId>Arch.System</PackageId>\r\n        <Title>Arch.System</Title>\r\n        <Version>1.1.0</Version>\r\n        <Authors>genaray</Authors>\r\n        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\r\n        <Description>A systems framework for arch.</Description>\r\n        <PackageReleaseNotes>Made group extendible. </PackageReleaseNotes>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <IsPackable>true</IsPackable>\r\n\r\n        <LangVersion>11</LangVersion>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageLicenseUrl></PackageLicenseUrl>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n\r\n        <UnityPublish>true</UnityPublish>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <None Update=\"Templates\\GenericAttributes.tt\">\r\n            <Generator>TextTemplatingFileGenerator</Generator>\r\n            <LastGenOutput>GenericAttributes.cs</LastGenOutput>\r\n        </None>\r\n    </ItemGroup>\r\n    \r\n    <ItemGroup>\r\n      <Service Include=\"{508349b6-6b84-4df5-91f0-309beebad82d}\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n      <Compile Update=\"Templates\\GenericAttributes.cs\">\r\n        <DesignTime>True</DesignTime>\r\n        <AutoGen>True</AutoGen>\r\n        <DependentUpon>GenericAttributes.tt</DependentUpon>\r\n      </Compile>\r\n    </ItemGroup>\r\n</Project>\r\n"
  },
  {
    "path": "Arch.System/Attributes.cs",
    "content": "﻿namespace Arch.System;\r\n\r\n/// <summary>\r\n///     Marks a method to generate a high performance query for it. \r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Method)]\r\npublic class QueryAttribute : global::System.Attribute\r\n{\r\n    /// <summary>\r\n    /// If set to true, Query will be run in parallel.\r\n    /// </summary>\r\n    public bool Parallel { get; set; }\r\n}\r\n\r\n/// <summary>\r\n///     Marks a parameter as \"data\". This will be taken into account during source generation and will still be passed as a parameter in the query method.\r\n///     Is not treated as an entity component.\r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Parameter)]\r\npublic class DataAttribute : global::System.Attribute\r\n{\r\n}\r\n\r\n/// <summary>\r\n///     Defines a set of components each entity requires. \r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]\r\npublic class AllAttribute : global::System.Attribute\r\n{\r\n    /// <summary>\r\n    /// The types of the component.\r\n    /// </summary>\r\n    public Type[] ComponentTypes { get; }\r\n\r\n    /// <summary>\r\n    /// Constructs an All attribute with the specified component types.\r\n    /// </summary>\r\n    /// <param name=\"componentTypes\">The types of the components that should be present.</param>\r\n    public AllAttribute(params Type[] componentTypes)\r\n    {\r\n        ComponentTypes = componentTypes;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     Defines a set of components each entity requires any from. \r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]\r\npublic class AnyAttribute : global::System.Attribute\r\n{\r\n    /// <summary>\r\n    /// The types of the component.\r\n    /// </summary>\r\n    public Type[] ComponentTypes { get; }\r\n\r\n    /// <summary>\r\n    /// Constructs an Any attribute with the specified component types.\r\n    /// </summary>\r\n    /// <param name=\"componentTypes\">The types of the components that can be present.</param>\r\n    public AnyAttribute(params Type[] componentTypes)\r\n    {\r\n        ComponentTypes = componentTypes;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     Defines a set of components none of the entities should have. \r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]\r\npublic class NoneAttribute : global::System.Attribute\r\n{\r\n\r\n    /// <summary>\r\n    /// The types of the component.\r\n    /// </summary>\r\n    public Type[] ComponentTypes { get; }\r\n\r\n    /// <summary>\r\n    /// Constructs a None attribute with the specified component types.\r\n    /// </summary>\r\n    /// <param name=\"componentTypes\">The types of the components that should not be present.</param>\r\n    public NoneAttribute(params Type[] componentTypes)\r\n    {\r\n        ComponentTypes = componentTypes;\r\n    }\r\n}\r\n\r\n/// <summary>\r\n///     Defines an exclusive set of components an entity should have. \r\n/// </summary>\r\n[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]\r\npublic class ExclusiveAttribute : global::System.Attribute\r\n{\r\n    /// <summary>\r\n    /// The types of the component.\r\n    /// </summary>\r\n    public Type[] ComponentTypes { get; }\r\n\r\n    /// <summary>\r\n    /// Constructs an exclusive attribute with the specified component types.\r\n    /// </summary>\r\n    /// <param name=\"componentTypes\">The types of the components that should be present exclusively.</param>\r\n    public ExclusiveAttribute(params Type[] componentTypes)\r\n    {\r\n        ComponentTypes = componentTypes;\r\n    }\r\n}"
  },
  {
    "path": "Arch.System/Systems.cs",
    "content": "﻿//#if !NET5_0_OR_GREATER\r\n    #define ARCH_METRICS_DISABLED\r\n//#endif\r\n\r\nusing System.Collections;\r\nusing System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Text;\r\n\r\n#if !ARCH_METRICS_DISABLED\r\nusing System.Diagnostics.Metrics;\r\n#endif\r\n\r\nnamespace Arch.System;\r\n\r\n/// <summary>\r\n///     An interface providing several methods for a system. \r\n/// </summary>\r\n/// <typeparam name=\"T\">The type passed to each method. For example a delta time or some other data.</typeparam>\r\npublic interface ISystem<T> : IDisposable\r\n{\r\n    /// <summary>\r\n    ///     Initializes a system, before its first ever run.\r\n    /// </summary>\r\n    void Initialize();\r\n    \r\n    /// <summary>\r\n    ///     Runs before <see cref=\"Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to it.</param>\r\n    void BeforeUpdate(in T t);\r\n    \r\n    /// <summary>\r\n    ///     Updates the system.\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to it.</param>\r\n    void Update(in T t);\r\n    \r\n    /// <summary>\r\n    ///     Runs after <see cref=\"Update\"/>.\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to it.</param>\r\n    void AfterUpdate(in T t);\r\n}\r\n\r\n/// <summary>\r\n///     A basic implementation of a <see cref=\"ISystem{T}\"/>.\r\n/// </summary>\r\n/// <typeparam name=\"W\">The world type.</typeparam>\r\n/// <typeparam name=\"T\">The type passed to the <see cref=\"ISystem{T}\"/> interface.</typeparam>\r\npublic abstract class BaseSystem<W, T> : ISystem<T>\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Creates an instance. \r\n    /// </summary>\r\n    /// <param name=\"world\">The <see cref=\"World\"/>.</param>\r\n    protected BaseSystem(W world)\r\n    {\r\n        World = world;\r\n    }\r\n \r\n    /// <summary>\r\n    ///     The world instance. \r\n    /// </summary>\r\n    public W World { get; private set; }\r\n\r\n    /// <inheritdoc />\r\n    public virtual void Initialize(){}\r\n\r\n    /// <inheritdoc />\r\n    public virtual void BeforeUpdate(in T t) { }\r\n\r\n    /// <inheritdoc />\r\n    public virtual void Update(in T t){}\r\n\r\n    /// <inheritdoc />\r\n    public virtual void AfterUpdate(in T t){}\r\n\r\n    /// <inheritdoc />\r\n    public virtual void Dispose(){}\r\n}\r\n\r\n/// <summary>\r\n///     A group of <see cref=\"ISystem{T}\"/>'s to organize them.\r\n///     They will run in order.\r\n/// </summary>\r\n/// <typeparam name=\"T\">The type passed to the <see cref=\"ISystem{T}\"/>.</typeparam>\r\npublic class Group<T> : ISystem<T>, IEnumerable<ISystem<T>>\r\n{\r\n#if !ARCH_METRICS_DISABLED\r\n    private readonly Meter _meter;\r\n    private readonly Stopwatch _timer = new();\r\n#endif\r\n\r\n    /// <summary>\r\n    /// A unique name to identify this group\r\n    /// </summary>\r\n    public string Name { get; }\r\n\r\n    /// <summary>\r\n    /// All <see cref=\"SystemEntry\"/>'s in this group. \r\n    /// </summary>\r\n    private readonly List<SystemEntry> _systems = new();\r\n\r\n    /// <summary>\r\n    ///     Creates an instance with an array of <see cref=\"ISystem{T}\"/>'s that will belong to this group.\r\n    /// </summary>\r\n    /// <param name=\"name\">A unique name to identify this group</param>\r\n    /// <param name=\"systems\">An <see cref=\"ISystem{T}\"/> array.</param>\r\n    public Group(string name, params ISystem<T>[] systems)\r\n        : this(name, (IEnumerable<ISystem<T>>)systems)\r\n    {\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Creates an instance with an <see cref=\"IEnumerable{T}\"/> of <see cref=\"ISystem{T}\"/>'s that will belong to this group.\r\n    /// </summary>\r\n    /// <param name=\"name\">A unique name to identify this group</param>\r\n    /// <param name=\"systems\">An <see cref=\"IEnumerable{T}\"/> of <see cref=\"ISystem{T}\"/>.</param>\r\n    public Group(string name, IEnumerable<ISystem<T>> systems)\r\n    {\r\n        Name = name;\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n        _meter = new Meter(name);\r\n#endif\r\n\r\n#if NET5_0_OR_GREATER\r\n        // If possible expand the list before adding all the systems\r\n        if (systems.TryGetNonEnumeratedCount(out var count))\r\n            _systems.Capacity = count;\r\n#endif\r\n\r\n        foreach (var system in systems)\r\n            Add(system);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds several new <see cref=\"ISystem{T}\"/>'s to this group.\r\n    /// </summary>\r\n    /// <param name=\"systems\">An <see cref=\"ISystem{T}\"/> array.</param>\r\n    /// <returns>The same <see cref=\"Group{T}\"/>.</returns>\r\n    public Group<T> Add(params ISystem<T>[] systems)\r\n    {\r\n        _systems.Capacity = Math.Max(_systems.Capacity, _systems.Count + systems.Length);\r\n\r\n        foreach (var system in systems)\r\n            Add(system);\r\n\r\n        return this;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Adds an single <see cref=\"ISystem{T}\"/> to this group by its generic.\r\n    ///     Automatically initializes it properly. Must be contructorless.\r\n    /// </summary>\r\n    /// <typeparam name=\"G\">Its generic type.</typeparam>\r\n    /// <returns>The same <see cref=\"Group{T}\"/>.</returns>\r\n    public Group<T> Add<G>() where G : ISystem<T>, new()\r\n    {\r\n        return Add(new G());\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds an single <see cref=\"ISystem{T}\"/> to this group.\r\n    /// </summary>\r\n    /// <param name=\"system\"></param>\r\n    /// <returns></returns>\r\n    public Group<T> Add(ISystem<T> system)\r\n    {\r\n        _systems.Add(new SystemEntry(system\r\n#if !ARCH_METRICS_DISABLED\r\n            , _meter\r\n#endif\r\n        ));\r\n\r\n        return this;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Return the first <typeparamref name=\"G\"/> which was found in the hierachy.\r\n    /// </summary>\r\n    /// <typeparam name=\"G\">The Type.</typeparam>\r\n    /// <returns></returns>\r\n    public G Get<G>() where G : ISystem<T>\r\n    {\r\n        foreach (var item in _systems)\r\n        {\r\n            if (item.System is G sys)\r\n            {\r\n                return sys;\r\n            }\r\n\r\n            if (item.System is not Group<T> grp)\r\n            {\r\n                continue;\r\n            }\r\n\r\n            return grp.Get<G>();\r\n        }\r\n\r\n        return default;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Finds all <see cref=\"ISystem{T}\"/>s which can be cast into the given type.\r\n    /// </summary>\r\n    /// <typeparam name=\"G\">The Type.</typeparam>\r\n    /// <returns></returns>\r\n    public IEnumerable<G> Find<G>() where G : ISystem<T>\r\n    {\r\n        foreach (var item in _systems)\r\n        {\r\n            if (item.System is G sys)\r\n            {\r\n                yield return sys;\r\n            }\r\n\r\n            if (item.System is not Group<T> grp)\r\n            {\r\n                continue;\r\n            }\r\n            \r\n            foreach (var nested in grp.Find<G>())\r\n            {\r\n                yield return nested;   \r\n            }\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Initializes all <see cref=\"ISystem{T}\"/>'s in this <see cref=\"Group{T}\"/>.\r\n    /// </summary>\r\n    public void Initialize()\r\n    {\r\n        for (var index = 0; index < _systems.Count; index++)\r\n        {\r\n            var entry = _systems[index];\r\n            entry.System.Initialize();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Runs <see cref=\"ISystem{T}.BeforeUpdate\"/> on each <see cref=\"ISystem{T}\"/> of this <see cref=\"Group{T}\"/>..\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to each <see cref=\"ISystem{T}.Initialize\"/> method.</param>\r\n    public void BeforeUpdate(in T t)\r\n    {\r\n        for (var index = 0; index < _systems.Count; index++)\r\n        {\r\n            var entry = _systems[index];\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            _timer.Restart();\r\n            {\r\n#endif\r\n\r\n                entry.System.BeforeUpdate(in t);\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            }\r\n            _timer.Stop();\r\n            entry.BeforeUpdate.Record(_timer.Elapsed.TotalMilliseconds);\r\n#endif\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Runs <see cref=\"ISystem{T}.Update\"/> on each <see cref=\"ISystem{T}\"/> of this <see cref=\"Group{T}\"/>..\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to each <see cref=\"ISystem{T}.Initialize\"/> method.</param>\r\n    public void Update(in T t)\r\n    {\r\n        for (var index = 0; index < _systems.Count; index++)\r\n        {\r\n            var entry = _systems[index];\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            _timer.Restart();\r\n            {\r\n#endif\r\n\r\n                entry.System.Update(in t);\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            }\r\n            _timer.Stop();\r\n            entry.Update.Record(_timer.Elapsed.TotalMilliseconds);\r\n#endif\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Runs <see cref=\"ISystem{T}.AfterUpdate\"/> on each <see cref=\"ISystem{T}\"/> of this <see cref=\"Group{T}\"/>..\r\n    /// </summary>\r\n    /// <param name=\"t\">An instance passed to each <see cref=\"ISystem{T}.Initialize\"/> method.</param>\r\n    public void AfterUpdate(in T t)\r\n    {\r\n        for (var index = 0; index < _systems.Count; index++)\r\n        {\r\n            var entry = _systems[index];\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            _timer.Restart();\r\n            {\r\n#endif\r\n\r\n                entry.System.AfterUpdate(in t);\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            }\r\n            _timer.Stop();\r\n            entry.AfterUpdate.Record(_timer.Elapsed.TotalMilliseconds);\r\n#endif\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Disposes this <see cref=\"Group{T}\"/> and all <see cref=\"ISystem{T}\"/>'s within.\r\n    /// </summary>\r\n    public void Dispose()\r\n    {\r\n        foreach (var system in _systems)\r\n        {\r\n            system.Dispose();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Converts this <see cref=\"Group{T}\"/> to a human readable string.\r\n    /// </summary>\r\n    /// <returns></returns>\r\n    public override string ToString()\r\n    {\r\n        // List all system names\r\n        var stringBuilder = new StringBuilder();\r\n        foreach (var systemEntry in _systems)\r\n        {\r\n            stringBuilder.Append($\"{systemEntry.System.GetType().Name},\");\r\n        }\r\n\r\n        // Cut last `,`\r\n        if (_systems.Count > 0)\r\n        {\r\n            stringBuilder.Length--;\r\n        }\r\n        \r\n        return $\"Group = {{ {nameof(Name)} = {Name}, Systems = {{ {stringBuilder} }} }} \";\r\n    }\r\n    \r\n    /// <inheritdoc/>\r\n    public IEnumerator<ISystem<T>> GetEnumerator()\r\n    {\r\n        foreach (var entry in _systems)\r\n        {\r\n            yield return entry.System;\r\n        }\r\n    }\r\n\r\n    /// <inheritdoc/>\r\n    IEnumerator IEnumerable.GetEnumerator()\r\n    {\r\n        return GetEnumerator();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     The struct <see cref=\"SystemEntry\"/> represents the given <see cref=\"ISystem{T}\"/> in the <see cref=\"Group{T}\"/> with all its performance statistics.\r\n    /// </summary>\r\n    private readonly struct SystemEntry : IDisposable\r\n    {\r\n        public readonly ISystem<T> System;\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n        public readonly Histogram<double> BeforeUpdate;\r\n        public readonly Histogram<double> Update;\r\n        public readonly Histogram<double> AfterUpdate;\r\n#endif\r\n\r\n        public void Dispose()\r\n        {\r\n            System.Dispose();\r\n        }\r\n\r\n        public SystemEntry(ISystem<T> system\r\n#if !ARCH_METRICS_DISABLED\r\n                , Meter meter\r\n#endif\r\n            )\r\n        {\r\n            var name = system.GetType().Name;\r\n            System = system;\r\n\r\n#if !ARCH_METRICS_DISABLED\r\n            BeforeUpdate = meter.CreateHistogram<double>($\"{name}.BeforeUpdate\", unit: \"millisecond\");\r\n            Update = meter.CreateHistogram<double>($\"{name}.Update\", unit: \"millisecond\");\r\n            AfterUpdate = meter.CreateHistogram<double>($\"{name}.AfterUpdate\", unit: \"millisecond\");\r\n#endif\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System/Templates/GenericAttributes.cs",
    "content": "namespace Arch.System;\r\n\r\n#if NET7_0_OR_GREATER\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AllAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> : AllAttribute\r\n{\r\n    /// <inheritdoc cref=\"AllAttribute.AllAttribute\" />\r\n    public AllAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23), typeof(T24)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class AnyAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> : AnyAttribute\r\n{\r\n    /// <inheritdoc cref=\"AnyAttribute.AnyAttribute\" />\r\n    public AnyAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23), typeof(T24)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class NoneAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> : NoneAttribute\r\n{\r\n    /// <inheritdoc cref=\"NoneAttribute.NoneAttribute\" />\r\n    public NoneAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23), typeof(T24)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23)) { }\r\n}\r\n\r\n/// <inheritdoc/>\r\npublic class ExclusiveAttribute<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> : ExclusiveAttribute\r\n{\r\n    /// <inheritdoc cref=\"ExclusiveAttribute.ExclusiveAttribute\" />\r\n    public ExclusiveAttribute() : base(typeof(T0), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20), typeof(T21), typeof(T22), typeof(T23), typeof(T24)) { }\r\n}\r\n\r\n#endif\r\n"
  },
  {
    "path": "Arch.System/Templates/GenericAttributes.tt",
    "content": "namespace Arch.System;\r\n<#@ template language=\"C#\" #>\r\n<#@ output extension=\".cs\" #>\r\n<#@ import namespace=\"System.Text\" #>\r\n<#@ include file=\"Helpers.ttinclude\" #>\r\n#if NET7_0_OR_GREATER\r\n\r\n<#\r\n    var names = new string[] { \"All\", \"Any\", \"None\", \"Exclusive\" };\r\n    foreach (var name in names)\r\n    {\r\n        for (var index = 1; index <= Amount; index++)\r\n        {\r\n            var generics = AppendGenerics(index);\r\n            var parameters = AppendGenericTypeParameters(index);\r\n#>\r\n/// <inheritdoc/>\r\npublic class <#= name #>Attribute<<#= generics #>> : <#= name #>Attribute\r\n{\r\n    /// <inheritdoc cref=\"<#= name #>Attribute.<#= name #>Attribute\" />\r\n    public <#= name #>Attribute() : base(<#= parameters #>) { }\r\n}\r\n\r\n<#\r\n        }\r\n    }\r\n#>\r\n#endif\r\n"
  },
  {
    "path": "Arch.System/Templates/Helpers.ttinclude",
    "content": "﻿<#@ import namespace=\"System.Text\" #>\r\n<#@ import namespace=\"System.Collections.Generic\" #>\r\n<#+\r\n    public int Amount = 25;\r\n\r\n    public string Indent(StringBuilder sb, int spaces)\r\n    {\r\n        var indent = new string(' ', spaces);\r\n        return sb.ToString().Replace(\"\\n\", \"\\n\" + indent);\r\n    }\r\n\r\n    string AppendGenerics(int amount)\r\n    {\r\n        var sb = new StringBuilder();\r\n        for (var i = 0; i < amount; i++)\r\n        {\r\n            if (i > 0) sb.Append(\", \");\r\n            sb.Append($\"T{i}\");\r\n        }\r\n        return sb.ToString();\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Lists generic types in a row as parameters.\r\n    ///     <example>\r\n    ///         <code>\r\n    ///             typeof(T0), typeof(T1), ...\r\n    ///         </code>\r\n    ///     </example>\r\n    /// </summary>\r\n    /// <param name=\"sb\"></param>\r\n    /// <param name=\"amount\"></param>\r\n    /// <returns></returns>\r\n    public StringBuilder AppendGenericTypeParameters(int amount)\r\n    {\r\n        var sb = new StringBuilder();\r\n        for (var localIndex = 0; localIndex < amount; localIndex++)\r\n        {\r\n            sb.Append($\"typeof(T{localIndex}), \");\r\n        }\r\n\r\n        sb.Length -= 2;\r\n        return sb;\r\n    }\r\n#>"
  },
  {
    "path": "Arch.System.SourceGenerator/Arch.System.SourceGenerator.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n    <PropertyGroup>\r\n        <TargetFramework>netstandard2.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <LangVersion>latest</LangVersion>\r\n\r\n        <GenerateDocumentationFile>true</GenerateDocumentationFile>\r\n        <DocumentationFile>bin\\$(Configuration)\\$(TargetFramework)\\$(AssemblyName).xml</DocumentationFile>\r\n        <IncludeSymbols>true</IncludeSymbols>\r\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\r\n\r\n        <PackageId>Arch.System.SourceGenerator</PackageId>\r\n        <Title>Arch.System.SourceGenerator</Title>\r\n        <Version>2.1.0</Version>\r\n        <Authors>genaray</Authors>\r\n        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\r\n        <Description>A source generator for arch.system.</Description>\r\n        <PackageReleaseNotes>Updated to fit Arch 2.1.0-beta and upwards. </PackageReleaseNotes>\r\n        <PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;</PackageTags>\r\n\r\n        <PackageProjectUrl>https://github.com/genaray/Arch.Extended</PackageProjectUrl>\r\n        <RepositoryUrl>https://github.com/genaray/Arch.Extended.git</RepositoryUrl>\r\n        <RepositoryType>git</RepositoryType>\r\n        <IsPackable>true</IsPackable>\r\n\r\n        <LangVersion>12</LangVersion>\r\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n        <Copyright>Apache2.0</Copyright>\r\n        <PackageLicenseUrl></PackageLicenseUrl>\r\n        <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"4.1.0\" PrivateAssets=\"analyzers\" />\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n        <None Include=\"$(OutputPath)\\$(AssemblyName).dll\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\r\n    </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator/Extensions/CommonUtils.cs",
    "content": "﻿using System.Text;\r\nusing Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.System.SourceGenerator;\r\n\r\n/// <summary>\r\n/// Common utils.\r\n/// </summary>\r\npublic static class CommonUtils\r\n{\r\n    \r\n    /// <summary>\r\n    ///     Convert a <see cref=\"RefKind\"/> to its code string equivalent.\r\n    /// </summary>\r\n    /// <param name=\"refKind\">The <see cref=\"RefKind\"/>.</param>\r\n    /// <returns>The code string equivalent.</returns>\r\n    public static string RefKindToString(RefKind refKind)\r\n    {\r\n        switch (refKind)\r\n        {\r\n            case RefKind.None:\r\n                return \"\";\r\n            case RefKind.Ref:\r\n                return \"ref\";\r\n            case RefKind.In:\r\n                return \"in\";\r\n            case RefKind.Out:\r\n                return \"out\";\r\n        }\r\n        return null!;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a list of generic type parameters separated by a simple comma.\r\n    ///     <example>T0,T1,..TN</example> \r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"amount\">The amount of generic type parameters.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder GenericsWithoutBrackets(this StringBuilder sb, int amount)\r\n    {\r\n        for (var i = 0; i < amount; i++)\r\n            sb.Append($\"T{i},\");\r\n        if (sb.Length > 0) sb.Length -= 1;\r\n\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a list of generic type parameters types separated by a simple comma.\r\n    ///     <example>typeof(T0),typeof(T1),..typeof(TN)</example> \r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"amount\">The amount of generic type parameters.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder GenericsToTypeArray(this StringBuilder sb, int amount)\r\n    {\r\n        for (var i = 0; i < amount; i++)\r\n            sb.Append($\"typeof(T{i}),\");\r\n        if (sb.Length > 0) sb.Length -= 1;\r\n\r\n        return sb;\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator/Extensions/MethodSymbolExtensions.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.System.SourceGenerator;\r\n\r\n/// <summary>\r\n/// Extensions for <see cref=\"IMethodSymbol\"/>.\r\n/// </summary>\r\npublic static class MethodSymbolExtensions\r\n{\r\n\r\n    /// <summary>\r\n    ///     Searches attributes of a <see cref=\"IMethodSymbol\"/> and returns the first one found.\r\n    /// </summary>\r\n    /// <param name=\"ms\">The <see cref=\"IMethodSymbol\"/> instance.</param>\r\n    /// <param name=\"name\">The attributes name.</param>\r\n    /// <returns>The attribute wrapped in an <see cref=\"AttributeData\"/>.</returns>\r\n    public static AttributeData GetAttributeData(this IMethodSymbol ms, string name)\r\n    {\r\n        foreach (var attribute in ms.GetAttributes())\r\n        {\r\n            var classSymbol = attribute.AttributeClass;\r\n            if(!classSymbol!.Name.Contains(name)) continue;\r\n\r\n            return attribute;\r\n        }\r\n\r\n        return default!;\r\n    }\r\n    \r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator/Model.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.System.SourceGenerator;\r\n\r\n/// <summary>\r\n/// Represents the BaseSystem that is generated and calls its generated query methods.  \r\n/// </summary>\r\npublic struct BaseSystem\r\n{\r\n    /// <summary>\r\n    /// The namespace its generic is in.\r\n    /// </summary>\r\n    public string GenericTypeNamespace { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The namespace this system is in. \r\n    /// </summary>\r\n    public string Namespace { get; set; }\r\n    \r\n    /// <summary>\r\n    /// Its name.\r\n    /// </summary>\r\n    public string Name { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The generic type. \r\n    /// </summary>\r\n    public ITypeSymbol GenericType { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The Query methods this base system calls one after another. \r\n    /// </summary>\r\n    public IList<IMethodSymbol> QueryMethods { get; set; }\r\n}\r\n\r\n/// <summary>\r\n/// Represents the Query method that is generated. \r\n/// </summary>\r\npublic struct QueryMethod\r\n{\r\n    /// <summary>\r\n    /// If the class containing this Query method is within the global namespace.\r\n    /// </summary>\r\n    public bool IsGlobalNamespace { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The namespace of the method.\r\n    /// </summary>\r\n    public string Namespace { get; set; }\r\n    \r\n    /// <summary>\r\n    /// If this method is static.\r\n    /// </summary>\r\n    public bool IsStatic { get; set; }\r\n    \r\n    /// <summary>\r\n    /// If this Query method contains an Entity as a param and acesses it. \r\n    /// </summary>\r\n    public bool IsEntityQuery { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The name of the class containing this Query method.\r\n    /// </summary>\r\n    public string ClassName { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The name of the Query method.\r\n    /// </summary>\r\n    public string MethodName { get; set; }\r\n    \r\n    /// <summary>\r\n    /// The entity parameter, if its an entity query. \r\n    /// </summary>\r\n    public IParameterSymbol EntityParameter { get; set; }\r\n    \r\n    /// <summary>\r\n    /// All parameters within the query method, not only the components. Also Entity and Data annotated ones.\r\n    /// <remarks>public void Query([Data] float time, in Entity entity, ...);</remarks>\r\n    /// </summary>\r\n    public IList<IParameterSymbol> Parameters { get; set; }\r\n\r\n    /// <summary>\r\n    /// The Components acessed within the query method.\r\n    /// <remarks>public void Query(ref Position pos, in Velocity vel){}</remarks>\r\n    /// </summary>\r\n    public IList<IParameterSymbol> Components { get; set; }\r\n    \r\n    /// <summary>\r\n    /// All <see cref=\"ITypeSymbol\"/>s mentioned in the All annotation query filter.\r\n    /// <remarks>[All(typeof(Position), typeof(Velocity)] or its generic variant</remarks>\r\n    /// </summary>\r\n    public IList<ITypeSymbol> AllFilteredTypes { get; set; }\r\n    \r\n    /// <summary>\r\n    /// All <see cref=\"ITypeSymbol\"/>s mentioned in the Any annotation query filter.\r\n    /// <remarks>[Any(typeof(Position), typeof(Velocity)] or its generic variant</remarks>\r\n    /// </summary>\r\n    public IList<ITypeSymbol> AnyFilteredTypes { get; set; }\r\n    \r\n    /// <summary>\r\n    /// All <see cref=\"ITypeSymbol\"/>s mentioned in the None annotation query filter.\r\n    /// <remarks>[None(typeof(Position), typeof(Velocity)] or its generic variant</remarks>\r\n    /// </summary>\r\n    public IList<ITypeSymbol> NoneFilteredTypes { get; set; }\r\n    \r\n    /// <summary>\r\n    /// All <see cref=\"ITypeSymbol\"/>s mentioned in the Exclusive annotation query filter.\r\n    /// <remarks>[Exclusive(typeof(Position), typeof(Velocity)] or its generic variant</remarks>\r\n    /// </summary>\r\n    public IList<ITypeSymbol> ExclusiveFilteredTypes { get; set; }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator/QueryUtils.cs",
    "content": "﻿using System.Text;\r\nusing Microsoft.CodeAnalysis;\r\n\r\nnamespace Arch.System.SourceGenerator;\r\n\r\n/// <summary>\r\n/// Various query utilities.\r\n/// </summary>\r\npublic static class QueryUtils\r\n{\r\n\r\n    /// <summary>\r\n    ///     Appends the first elements of the types specified in the <paramref name=\"parameterSymbols\"/> from the previous specified arrays.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> list of <see cref=\"IParameterSymbol\"/>s which we wanna append the first elements for.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder GetFirstElements(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n      \r\n        foreach (var symbol in parameterSymbols)\r\n            if(symbol.Type.Name is not \"Entity\" || !symbol.GetAttributes().Any(data => data.AttributeClass!.Name.Contains(\"Data\"))) // Prevent entity being added to the type array\r\n                sb.AppendLine($\"ref var @{symbol.Type.Name.ToLower()}FirstElement = ref chunk.GetFirst<{symbol.Type.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat)}>();\");\r\n\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends the components of the types specified in the <paramref name=\"parameterSymbols\"/> from the previous specified first elements.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> list of <see cref=\"IParameterSymbol\"/>s which we wanna append the components for.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder GetComponents(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n        foreach (var symbol in parameterSymbols)\r\n            if(symbol.Type.Name is not \"Entity\") // Prevent entity being added to the type array\r\n                sb.AppendLine($\"ref var @{symbol.Name.ToLower()} = ref Unsafe.Add(ref {symbol.Type.Name.ToLower()}FirstElement, entityIndex);\");\r\n\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Inserts the types defined in the <paramref name=\"parameterSymbols\"/> as parameters in a method.\r\n    ///     <example>ref position, out velocity,...</example>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> of <see cref=\"IParameterSymbol\"/>s which we wanna insert.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder InsertParams(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n        foreach (var symbol in parameterSymbols)\r\n            sb.Append($\"{CommonUtils.RefKindToString(symbol.RefKind)} @{symbol.Name.ToLower()},\");\r\n        \r\n        if(sb.Length > 0) sb.Length--;\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Creates a ComponentType array from the <paramref name=\"parameterSymbols\"/> passed through.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/>.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IList{T}\"/> with <see cref=\"ITypeSymbol\"/>s which we wanna create a ComponentType array for.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder GetTypeArray(this StringBuilder sb, IList<ITypeSymbol> parameterSymbols)\r\n    {\r\n        if (parameterSymbols.Count == 0)\r\n        {\r\n            sb.Append(\"Signature.Null\");\r\n            return sb;\r\n        }\r\n\r\n        sb.Append(\"new Signature(\");\r\n        \r\n        foreach (var symbol in parameterSymbols)\r\n            if(symbol.Name is not \"Entity\") // Prevent entity being added to the type array\r\n                sb.Append($\"typeof({symbol.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat)}),\");\r\n        \r\n        if (sb.Length > 0) sb.Length -= 1;\r\n        sb.Append(')');\r\n\r\n        return sb;\r\n    }\r\n\r\n\r\n    /// <summary>\r\n    ///     Appends a set of <paramref name=\"parameterSymbols\"/> if they are marked by the data attribute.\r\n    ///     <example>ref gameTime, out somePassedList,...</example>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> of <see cref=\"IParameterSymbol\"/>s which will be appended if they are marked with data.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder DataParameters(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n        sb.Append(',');\r\n        foreach (var parameter in parameterSymbols)\r\n        {\r\n            if (parameter.GetAttributes().Any(attributeData => attributeData.AttributeClass!.Name.Contains(\"Data\")))\r\n                sb.Append($\"{CommonUtils.RefKindToString(parameter.RefKind)} {parameter.Type} @{parameter.Name.ToLower()},\");\r\n        }\r\n        sb.Length--;\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends a set of <paramref name=\"parameterSymbols\"/> if they are marked by the data attribute.\r\n    ///     <example>ref gameTime, out somePassedList,...</example>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> of <see cref=\"IParameterSymbol\"/>s which will be appended if they are marked with data.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder JobParameters(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n        foreach (var parameter in parameterSymbols)\r\n        {\r\n            if (parameter.GetAttributes().Any(attributeData => attributeData.AttributeClass!.Name.Contains(\"Data\")))\r\n                sb.AppendLine($\"public {parameter.Type} @{parameter.Name.ToLower()};\");\r\n        }\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends a set of <paramref name=\"parameterSymbols\"/> if they are marked by the data attribute.\r\n    ///     <example>ref gameTime, out somePassedList,...</example>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"parameterSymbols\">The <see cref=\"IEnumerable{T}\"/> of <see cref=\"IParameterSymbol\"/>s which will be appended if they are marked with data.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder JobParametersAssigment(this StringBuilder sb, IEnumerable<IParameterSymbol> parameterSymbols)\r\n    {\r\n        bool found = false;\r\n        foreach (var parameter in parameterSymbols)\r\n        {\r\n            if (parameter.GetAttributes().Any(attributeData => attributeData.AttributeClass!.Name.Contains(\"Data\")))\r\n            {\r\n                found = true;\r\n                sb.Append($\"@{parameter.Name.ToLower()} = @{parameter.Name.ToLower()},\");\r\n            }\r\n        }\r\n        if (found) sb.Length--;\r\n        return sb;\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Appends method calls made with their important data parameters.\r\n    ///     <example>someQuery(World, gameTime); ...</example>\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"methodNames\">The <see cref=\"IEnumerable{T}\"/> of methods which we wanna call.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder CallMethods(this StringBuilder sb, IEnumerable<IMethodSymbol> methodNames)\r\n    {\r\n        foreach (var method in methodNames)\r\n        {\r\n            var data = new StringBuilder();\r\n            data.Append(',');\r\n            foreach (var parameter in method.Parameters)\r\n            {\r\n                if (!parameter.GetAttributes().Any(attributeData => attributeData.AttributeClass!.Name.Contains(\"Data\"))) continue;\r\n                data.Append($\"{CommonUtils.RefKindToString(parameter.RefKind)} data,\");\r\n                break;\r\n            }\r\n            data.Length--;\r\n            sb.AppendLine($\"{method.Name}Query(World {data});\");   \r\n        }\r\n        return sb;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Gets all the types of a <see cref=\"AttributeData\"/> as <see cref=\"ITypeSymbol\"/>s and adds them to a list.\r\n    ///     If the attribute is generic it will add the generic parameters, if its non generic it will add the non generic types from the constructor.\r\n    /// </summary>\r\n    /// <param name=\"data\">The <see cref=\"AttributeData\"/>.</param>\r\n    /// <param name=\"array\">The <see cref=\"List{T}\"/> where the found <see cref=\"ITypeSymbol\"/>s are added to.</param>\r\n    public static void GetAttributeTypes(AttributeData? data, List<ITypeSymbol> array)\r\n    {\r\n        if (data is not null && data.AttributeClass!.IsGenericType)\r\n        {\r\n            array.AddRange(data.AttributeClass.TypeArguments);\r\n        }\r\n        else if (data is not null && !data.AttributeClass!.IsGenericType)\r\n        {\r\n            var constructorArguments = data.ConstructorArguments[0].Values;\r\n            var constructorArgumentsTypes = constructorArguments.Select(constant => constant.Value as ITypeSymbol).ToList();\r\n            array.AddRange(constructorArgumentsTypes!);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds a query with an entity for a given annotated method. The attributes of these methods are used to generate the query.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"methodSymbol\">The <see cref=\"IMethodSymbol\"/> which is annotated for source generation.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendQueryMethod(this StringBuilder sb, IMethodSymbol methodSymbol)\r\n    {\r\n\r\n        // Check for entity param\r\n        var entity = methodSymbol.Parameters.Any(symbol => symbol.Type.Name.Equals(\"Entity\"));\r\n        var entityParam = entity ? methodSymbol.Parameters.First(symbol => symbol.Type.Name.Equals(\"Entity\")) : null;\r\n\r\n        var queryData = methodSymbol.GetAttributeData(\"Query\");\r\n        bool isParallel = (bool)(queryData.NamedArguments.FirstOrDefault(d => d.Key == \"Parallel\").Value.Value ?? false);\r\n\r\n        // Get attributes\r\n        var attributeData = methodSymbol.GetAttributeData(\"All\");\r\n        var anyAttributeData = methodSymbol.GetAttributeData(\"Any\");\r\n        var noneAttributeData = methodSymbol.GetAttributeData(\"None\");\r\n        var exclusiveAttributeData = methodSymbol.GetAttributeData(\"Exclusive\");\r\n        \r\n        // Get params / components except those marked with data or entities. \r\n        var components = methodSymbol.Parameters.ToList();\r\n        components.RemoveAll(symbol => symbol.Type.Name.Equals(\"Entity\"));                                                // Remove entitys \r\n        components.RemoveAll(symbol => symbol.GetAttributes().Any(data => data.AttributeClass!.Name.Contains(\"Data\")));    // Remove data annotated params\r\n        \r\n        // Create all query array\r\n        var allArray = components.Select(symbol => symbol.Type).ToList();\r\n        var anyArray = new List<ITypeSymbol>();\r\n        var noneArray = new List<ITypeSymbol>();\r\n        var exclusiveArray = new List<ITypeSymbol>();\r\n\r\n        // Get All<...> or All(...) passed types and pass them to the arrays \r\n        GetAttributeTypes(attributeData, allArray);\r\n        GetAttributeTypes(anyAttributeData, anyArray);\r\n        GetAttributeTypes(noneAttributeData, noneArray);\r\n        GetAttributeTypes(exclusiveAttributeData, exclusiveArray);\r\n        \r\n        // Remove doubles and entities \r\n        allArray = allArray.Distinct<ITypeSymbol>(SymbolEqualityComparer.Default).ToList();\r\n        anyArray = anyArray.Distinct<ITypeSymbol>(SymbolEqualityComparer.Default).ToList();\r\n        noneArray = noneArray.Distinct<ITypeSymbol>(SymbolEqualityComparer.Default).ToList();\r\n        exclusiveArray = exclusiveArray.Distinct<ITypeSymbol>(SymbolEqualityComparer.Default).ToList();\r\n        \r\n        allArray.RemoveAll(symbol => symbol.Name.Equals(\"Entity\")); \r\n        anyArray.RemoveAll(symbol => symbol.Name.Equals(\"Entity\"));\r\n        noneArray.RemoveAll(symbol => symbol.Name.Equals(\"Entity\"));\r\n        exclusiveArray.RemoveAll(symbol => symbol.Name.Equals(\"Entity\"));\r\n\r\n        // Create data modell and generate it\r\n        var className = methodSymbol.ContainingSymbol.ToString();\r\n        var queryMethod = new QueryMethod\r\n        {\r\n            IsGlobalNamespace = methodSymbol.ContainingNamespace.IsGlobalNamespace,\r\n            Namespace = methodSymbol.ContainingNamespace.ToString(),\r\n            ClassName = className.Substring(className.LastIndexOf('.')+1),\r\n            \r\n            IsStatic = methodSymbol.IsStatic,\r\n            IsEntityQuery = entity,\r\n            MethodName = methodSymbol.Name,\r\n            \r\n            EntityParameter = entityParam!,\r\n            Parameters = methodSymbol.Parameters,\r\n            Components = components,\r\n            \r\n            AllFilteredTypes = allArray,\r\n            AnyFilteredTypes = anyArray,\r\n            NoneFilteredTypes = noneArray,\r\n            ExclusiveFilteredTypes = exclusiveArray\r\n        };\r\n        \r\n        return isParallel ? sb.AppendParallelQueryMethod(ref queryMethod) : sb.AppendQueryMethod(ref queryMethod);\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds a query with an entity for a given annotated method. The attributes of these methods are used to generate the query.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"queryMethod\">The <see cref=\"QueryMethod\"/> which is generated.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendQueryMethod(this StringBuilder sb, ref QueryMethod queryMethod)\r\n    {\r\n        var staticModifier = queryMethod.IsStatic ? \"static\" : \"\";\r\n        \r\n        // Generate code \r\n        var data = new StringBuilder().DataParameters(queryMethod.Parameters);\r\n        var getFirstElements = new StringBuilder().GetFirstElements(queryMethod.Components);\r\n        var getComponents = new StringBuilder().GetComponents(queryMethod.Components);\r\n        var insertParams = new StringBuilder().InsertParams(queryMethod.Parameters);\r\n        \r\n        var allTypeArray = new StringBuilder().GetTypeArray(queryMethod.AllFilteredTypes);\r\n        var anyTypeArray = new StringBuilder().GetTypeArray(queryMethod.AnyFilteredTypes);\r\n        var noneTypeArray = new StringBuilder().GetTypeArray(queryMethod.NoneFilteredTypes);\r\n        var exclusiveTypeArray = new StringBuilder().GetTypeArray(queryMethod.ExclusiveFilteredTypes);\r\n\r\n        var template = \r\n            $$\"\"\"\r\n            #nullable enable\r\n            using System;\r\n            using System.Runtime.CompilerServices;\r\n            using System.Runtime.InteropServices;\r\n            using Arch.Core;\r\n            using Arch.Core.Extensions;\r\n            using Arch.Core.Utils;\r\n            using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\n            using Component = Arch.Core.Component;\r\n            {{(!queryMethod.IsGlobalNamespace ? $\"namespace {queryMethod.Namespace} {{\" : \"\")}}\r\n                partial class {{queryMethod.ClassName}}{\r\n                    \r\n                    private {{staticModifier}} QueryDescription {{queryMethod.MethodName}}_QueryDescription = new QueryDescription(\r\n                        all: {{allTypeArray}},\r\n                        any: {{anyTypeArray}},\r\n                        none: {{noneTypeArray}},\r\n                        exclusive: {{exclusiveTypeArray}}\r\n                    );\r\n\r\n                    private {{staticModifier}} World? _{{queryMethod.MethodName}}_Initialized;\r\n                    private {{staticModifier}} Query? _{{queryMethod.MethodName}}_Query;\r\n\r\n                    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n                    public {{staticModifier}} void {{queryMethod.MethodName}}Query(World world {{data}}){\r\n                     \r\n                        if(!ReferenceEquals(_{{queryMethod.MethodName}}_Initialized, world)) {\r\n                            _{{queryMethod.MethodName}}_Query = world.Query(in {{queryMethod.MethodName}}_QueryDescription);\r\n                            _{{queryMethod.MethodName}}_Initialized = world;\r\n                        }\r\n\r\n                        foreach(ref var chunk in _{{queryMethod.MethodName}}_Query!){\r\n                            \r\n                            {{(queryMethod.IsEntityQuery ? \"ref var entityFirstElement = ref chunk.Entity(0);\" : \"\")}}\r\n                            {{getFirstElements}}\r\n\r\n                            foreach(var entityIndex in chunk)\r\n                            {\r\n                                {{(queryMethod.IsEntityQuery ? $\"ref readonly var {queryMethod.EntityParameter.Name.ToLower()} = ref Unsafe.Add(ref entityFirstElement, entityIndex);\" : \"\")}}\r\n                                {{getComponents}}\r\n                                {{queryMethod.MethodName}}({{insertParams}});\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            {{(!queryMethod.IsGlobalNamespace ? \"}\" : \"\")}}\r\n            \"\"\";\r\n\r\n        sb.Append(template);\r\n        return sb;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds a parallel query with an entity for a given annotated method. The attributes of these methods are used to generate the query.\r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"queryMethod\">The <see cref=\"QueryMethod\"/> which is generated.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendParallelQueryMethod(this StringBuilder sb, ref QueryMethod queryMethod)\r\n    {\r\n        var staticModifier = queryMethod.IsStatic ? \"static\" : \"\";\r\n        \r\n        // Generate code \r\n        var jobParameters = new StringBuilder().JobParameters(queryMethod.Parameters);\r\n        var jobParametersAssigment = new StringBuilder().JobParametersAssigment(queryMethod.Parameters);\r\n        var data = new StringBuilder().DataParameters(queryMethod.Parameters);\r\n        var getFirstElements = new StringBuilder().GetFirstElements(queryMethod.Components);\r\n        var getComponents = new StringBuilder().GetComponents(queryMethod.Components);\r\n        var insertParams = new StringBuilder().InsertParams(queryMethod.Parameters);\r\n        \r\n        var allTypeArray = new StringBuilder().GetTypeArray(queryMethod.AllFilteredTypes);\r\n        var anyTypeArray = new StringBuilder().GetTypeArray(queryMethod.AnyFilteredTypes);\r\n        var noneTypeArray = new StringBuilder().GetTypeArray(queryMethod.NoneFilteredTypes);\r\n        var exclusiveTypeArray = new StringBuilder().GetTypeArray(queryMethod.ExclusiveFilteredTypes);\r\n\r\n        var template = \r\n            $$\"\"\"\r\n            #nullable enable\r\n            using System;\r\n            using System.Runtime.CompilerServices;\r\n            using System.Runtime.InteropServices;\r\n            using Arch.Core;\r\n            using Arch.Core.Extensions;\r\n            using Arch.Core.Utils;\r\n            using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\n            using Component = Arch.Core.Component;\r\n            {{(!queryMethod.IsGlobalNamespace ? $\"namespace {queryMethod.Namespace} {{\" : \"\")}}\r\n                partial class {{queryMethod.ClassName}}{\r\n                    \r\n                    private {{staticModifier}} QueryDescription {{queryMethod.MethodName}}_QueryDescription = new QueryDescription(\r\n                        all: {{allTypeArray}},\r\n                        any: {{anyTypeArray}},\r\n                        none: {{noneTypeArray}},\r\n                        exclusive: {{exclusiveTypeArray}}\r\n                    );\r\n\r\n                    private {{staticModifier}} World? _{{queryMethod.MethodName}}_Initialized;\r\n                    private {{staticModifier}} Query? _{{queryMethod.MethodName}}_Query;\r\n\r\n                    private struct {{queryMethod.MethodName}}QueryJobChunk : IChunkJob \r\n                    {\r\n                        {{jobParameters}}\r\n                        \r\n                        public void Execute(ref Chunk chunk) {\r\n                        \r\n                            {{(queryMethod.IsEntityQuery ? \"ref var entityFirstElement = ref chunk.Entity(0);\" : \"\")}}\r\n                            {{getFirstElements}}\r\n                    \r\n                            foreach(var entityIndex in chunk)\r\n                            {\r\n                                {{(queryMethod.IsEntityQuery ? $\"ref readonly var {queryMethod.EntityParameter.Name.ToLower()} = ref Unsafe.Add(ref entityFirstElement, entityIndex);\" : \"\")}}\r\n                                {{getComponents}}\r\n                                {{queryMethod.MethodName}}({{insertParams}});\r\n                            }\r\n                        }\r\n                    }\r\n            \r\n                    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n                    public {{staticModifier}} void {{queryMethod.MethodName}}Query(World world {{data}}){\r\n                     \r\n                        if(!ReferenceEquals(_{{queryMethod.MethodName}}_Initialized, world)) {\r\n                            _{{queryMethod.MethodName}}_Query = world.Query(in {{queryMethod.MethodName}}_QueryDescription);\r\n                            _{{queryMethod.MethodName}}_Initialized = world;\r\n                        }\r\n                        \r\n                        var job = new {{queryMethod.MethodName}}QueryJobChunk() { {{jobParametersAssigment}} };\r\n                        world.InlineParallelChunkQuery(in {{queryMethod.MethodName}}_QueryDescription, job);\r\n                    }\r\n                }\r\n            {{(!queryMethod.IsGlobalNamespace ? \"}\" : \"\")}}\r\n            \"\"\";\r\n\r\n        sb.Append(template);\r\n        return sb;\r\n    }\r\n\r\n    \r\n\r\n    /// <summary>\r\n    ///     Adds a basesystem that calls a bunch of query methods. \r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"classToMethod\">The <see cref=\"KeyValuePair{TKey,TValue}\"/> which maps all query methods to a common class containing them.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendBaseSystem(this StringBuilder sb, KeyValuePair<ISymbol, List<IMethodSymbol>> classToMethod)\r\n    {\r\n        // Get BaseSystem class\r\n        var classSymbol = classToMethod.Key as INamedTypeSymbol;\r\n\r\n        INamedTypeSymbol? parentSymbol = null;\r\n        var implementsUpdate = false;\r\n        var type = classSymbol;\r\n        while (type != null)\r\n        {\r\n            // Update was implemented by user, no need to do that by source generator.\r\n            if (type.GetMembers(\"Update\").OfType<IMethodSymbol>().Any(member => member.IsOverride))\r\n                implementsUpdate = true;\r\n\r\n            type = type.BaseType;\r\n\r\n            // Ignore classes which do not derive from BaseSystem\r\n            if (type?.Name == \"BaseSystem\")\r\n            {\r\n                parentSymbol = type;\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (parentSymbol == null || implementsUpdate)\r\n            return sb;\r\n\r\n        // Get generic of BaseSystem\r\n        var typeSymbol = parentSymbol.TypeArguments[1];\r\n\r\n        var className = classSymbol!.ToString();\r\n\r\n        // Generate basesystem.\r\n        var baseSystem = new BaseSystem\r\n        {\r\n            Namespace = classSymbol.ContainingNamespace != null && !classSymbol.ContainingNamespace.IsGlobalNamespace ? classSymbol.ContainingNamespace.ToString() : string.Empty,\r\n            GenericType = typeSymbol,\r\n            GenericTypeNamespace = typeSymbol.ContainingNamespace.ToString(),\r\n            Name = className.Substring(className.LastIndexOf('.') + 1),\r\n            QueryMethods = classToMethod.Value,\r\n        };\r\n        return sb.AppendBaseSystem(ref baseSystem);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Adds a basesystem that calls a bunch of query methods. \r\n    /// </summary>\r\n    /// <param name=\"sb\">The <see cref=\"StringBuilder\"/> instance.</param>\r\n    /// <param name=\"baseSystem\">The <see cref=\"BaseSystem\"/> which is generated.</param>\r\n    /// <returns></returns>\r\n    public static StringBuilder AppendBaseSystem(this StringBuilder sb, ref BaseSystem baseSystem)\r\n    {\r\n        var methodCalls = new StringBuilder().CallMethods(baseSystem.QueryMethods);\r\n        var template =\r\n            $$\"\"\"\r\n            using System.Runtime.CompilerServices;\r\n            using System.Runtime.InteropServices;\r\n            using {{baseSystem.GenericTypeNamespace}};\r\n            {{(baseSystem.Namespace != string.Empty ? $\"namespace {baseSystem.Namespace} {{\" : \"\")}}\r\n                partial class {{baseSystem.Name}}{\r\n                        \r\n                    [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n                    public override void Update(in {{baseSystem.GenericType.ToDisplayString()}} data){\r\n                        {{methodCalls}}\r\n                    }\r\n                }\r\n            {{(baseSystem.Namespace != string.Empty ? \"}\" : \"\")}}\r\n            \"\"\";\r\n        return sb.Append(template);\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator/SourceGenerator.cs",
    "content": "﻿using System.Collections.Immutable;\r\nusing System.Diagnostics;\r\nusing System.Text;\r\nusing Microsoft.CodeAnalysis;\r\nusing Microsoft.CodeAnalysis.CSharp;\r\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\r\nusing Microsoft.CodeAnalysis.Text;\r\n\r\nnamespace Arch.System.SourceGenerator;\r\n\r\n/// <summary>\r\n/// Generates queries.\r\n/// </summary>\r\n[Generator]\r\npublic class QueryGenerator : IIncrementalGenerator\r\n{\r\n    private static Dictionary<ISymbol, List<IMethodSymbol>> _classToMethods { get; set; } = null!;\r\n\r\n    /// <inheritdoc cref=\"IIncrementalGenerator.Initialize\"/>\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        //if (!Debugger.IsAttached) Debugger.Launch();\r\n\r\n        // Do a simple filter for methods marked with update\r\n        IncrementalValuesProvider<MethodDeclarationSyntax> methodDeclarations = context.SyntaxProvider.CreateSyntaxProvider(\r\n                 static (s, _) => s is MethodDeclarationSyntax { AttributeLists.Count: > 0 },\r\n                 static (ctx, _) => GetMethodSymbolIfAttributeof(ctx, \"Arch.System.QueryAttribute\")\r\n        ).Where(static m => m is not null)!; // filter out attributed methods that we don't care about\r\n\r\n        // Combine the selected enums with the `Compilation`\r\n        IncrementalValueProvider<(Compilation, ImmutableArray<MethodDeclarationSyntax>)> compilationAndMethods = context.CompilationProvider.Combine(methodDeclarations.WithComparer(Comparer.Instance).Collect());\r\n        context.RegisterSourceOutput(compilationAndMethods, static (spc, source) => Generate(source.Item1, source.Item2, spc));\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Adds a <see cref=\"IMethodSymbol\"/> to its class.\r\n    ///     Stores them in <see cref=\"_classToMethods\"/>.\r\n    /// </summary>\r\n    /// <param name=\"methodSymbol\">The <see cref=\"IMethodSymbol\"/> which will be added/mapped to its class.</param>\r\n    private static void AddMethodToClass(IMethodSymbol methodSymbol)\r\n    {\r\n        if (!_classToMethods.TryGetValue(methodSymbol.ContainingSymbol, out var list))\r\n        {\r\n            list = new List<IMethodSymbol>();\r\n            _classToMethods[methodSymbol.ContainingSymbol] = list;\r\n        }\r\n        list.Add(methodSymbol);\r\n    }\r\n    \r\n    /// <summary>\r\n    ///     Returns a <see cref=\"MethodDeclarationSyntax\"/> if it's annotated with an attribute of <paramref name=\"name\"/>.\r\n    /// </summary>\r\n    /// <param name=\"context\">Its <see cref=\"GeneratorSyntaxContext\"/>.</param>\r\n    /// <param name=\"name\">The attributes name.</param>\r\n    /// <returns></returns>\r\n    private static MethodDeclarationSyntax? GetMethodSymbolIfAttributeof(GeneratorSyntaxContext context, string name)\r\n    {\r\n        // we know the node is a EnumDeclarationSyntax thanks to IsSyntaxTargetForGeneration\r\n        var enumDeclarationSyntax = (MethodDeclarationSyntax)context.Node;\r\n\r\n        // loop through all the attributes on the method\r\n        foreach (var attributeListSyntax in enumDeclarationSyntax.AttributeLists)\r\n        {\r\n            foreach (var attributeSyntax in attributeListSyntax.Attributes)\r\n            {\r\n                if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) continue;\r\n                \r\n                var attributeContainingTypeSymbol = attributeSymbol.ContainingType;\r\n                var fullName = attributeContainingTypeSymbol.ToDisplayString();\r\n\r\n                // Is the attribute the [EnumExtensions] attribute?\r\n                if (fullName != name) continue;\r\n                return enumDeclarationSyntax;\r\n            }\r\n        }\r\n\r\n        // we didn't find the attribute we were looking for\r\n        return null;\r\n    }\r\n\r\n    /// <summary>\r\n    ///     Generates queries and partial classes for the found marked methods.\r\n    /// </summary>\r\n    /// <param name=\"compilation\">The <see cref=\"Compilation\"/>.</param>\r\n    /// <param name=\"methods\">The <see cref=\"ImmutableArray{MethodDeclarationSyntax}\"/> array, the methods which we will generate queries and classes for.</param>\r\n    /// <param name=\"context\">The <see cref=\"SourceProductionContext\"/>.</param>\r\n    private static void Generate(Compilation compilation, ImmutableArray<MethodDeclarationSyntax> methods, SourceProductionContext context)\r\n    {\r\n        if (methods.IsDefaultOrEmpty) return;\r\n        \r\n        // Generate Query methods and map them to their classes\r\n        _classToMethods = new(512, SymbolEqualityComparer.Default);\r\n        foreach (var methodSyntax in methods)\r\n        {\r\n            IMethodSymbol? methodSymbol = null;\r\n            try\r\n            {\r\n                var semanticModel = compilation.GetSemanticModel(methodSyntax.SyntaxTree);\r\n                methodSymbol = ModelExtensions.GetDeclaredSymbol(semanticModel, methodSyntax) as IMethodSymbol;\r\n            }\r\n            catch\r\n            {\r\n                //not update,skip\r\n                continue;\r\n            }\r\n\r\n            AddMethodToClass(methodSymbol!);\r\n            \r\n            var sb = new StringBuilder();\r\n            var method = sb.AppendQueryMethod(methodSymbol!);\r\n            var fileName = methodSymbol!.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat).Replace('<', '{').Replace('>', '}');\r\n            context.AddSource($\"{fileName}.g.cs\",CSharpSyntaxTree.ParseText(method.ToString()).GetRoot().NormalizeWhitespace().ToFullString());\r\n        }\r\n\r\n        // Creating class that calls the created methods after another.\r\n        foreach (var classToMethod in _classToMethods)\r\n        {\r\n            var template = new StringBuilder().AppendBaseSystem(classToMethod).ToString();\r\n            if (string.IsNullOrEmpty(template)) continue;\r\n            \r\n            var fileName = ((INamedTypeSymbol)classToMethod.Key).ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat).Replace('<', '{').Replace('>', '}');\r\n            context.AddSource($\"{fileName}.g.cs\",\r\n                CSharpSyntaxTree.ParseText(template).GetRoot().NormalizeWhitespace().ToFullString());\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Compares <see cref=\"MethodDeclarationSyntax\"/>s to remove duplicates. \r\n    /// </summary>\r\n    class Comparer : IEqualityComparer<MethodDeclarationSyntax>\r\n    {\r\n        public static readonly Comparer Instance = new();\r\n\r\n        public bool Equals(MethodDeclarationSyntax x, MethodDeclarationSyntax y)\r\n        {\r\n            return x.Equals(y);\r\n        }\r\n\r\n        public int GetHashCode(MethodDeclarationSyntax obj)\r\n        {\r\n            return obj.GetHashCode();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.SnapshotTests/.editorconfig",
    "content": "root = true\r\n\r\n# All files\r\n[*]\r\n\r\n# Indentation and spacing\r\nend_of_line              = crlf\r\nindent_style             = space\r\ntrim_trailing_whitespace = true\r\n\r\n# New line preferences\r\nend_of_line          = crlf\r\ninsert_final_newline = true\r\n\r\n# Xml project files\r\n[*.{csproj,proj,projitems,shproj,vbproj,vcxproj,vcxproj.filters}]\r\nindent_size = 2\r\n\r\n# Xml config files\r\n[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]\r\nindent_size = 2\r\n\r\n# Other markup files\r\n[*.{json,xml,yml,yaml}]\r\nindent_size = 2\r\n\r\n# Markdown files\r\n[*.md]\r\nindent_size              = 1\r\ntrim_trailing_whitespace = false\r\n\r\n# C# files\r\n[*.cs]\r\n\r\n#### Core EditorConfig Options ####\r\n\r\nfile_header_template = unset\r\n\r\n# Indentation and spacing\r\nindent_size = 4\r\n\r\n#### .NET Coding Conventions ####\r\n[*.{cs,vb}]\r\n\r\n# Organize usings\r\ndotnet_separate_import_directive_groups = false\r\ndotnet_sort_system_directives_first     = true\r\n\r\n# this. and Me. preferences\r\ndotnet_style_qualification_for_event    = false:warning\r\ndotnet_style_qualification_for_field    = false:warning\r\ndotnet_style_qualification_for_method   = false:warning\r\ndotnet_style_qualification_for_property = false:warning\r\n\r\n# Language keywords vs BCL types preferences\r\ndotnet_style_predefined_type_for_locals_parameters_members = true:warning\r\ndotnet_style_predefined_type_for_member_access             = true:warning\r\n\r\n# Parentheses preferences\r\ndotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning\r\ndotnet_style_parentheses_in_other_binary_operators      = always_for_clarity:warning\r\ndotnet_style_parentheses_in_other_operators             = never_if_unnecessary:warning\r\ndotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning\r\n\r\n# Modifier preferences\r\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:warning\r\n\r\n# Expression-level preferences\r\ndotnet_style_coalesce_expression                                 = true:suggestion\r\ndotnet_style_collection_initializer                              = true:warning\r\ndotnet_style_explicit_tuple_names                                = true:warning\r\ndotnet_style_null_propagation                                    = true:suggestion\r\ndotnet_style_object_initializer                                  = true:warning\r\ndotnet_style_operator_placement_when_wrapping                    = beginning_of_line\r\ndotnet_style_prefer_auto_properties                              = true:warning\r\ndotnet_style_prefer_compound_assignment                          = true:warning\r\ndotnet_style_prefer_conditional_expression_over_assignment       = true:suggestion\r\ndotnet_style_prefer_conditional_expression_over_return           = false:silent\r\ndotnet_style_prefer_foreach_explicit_cast_in_source              = when_strongly_typed\r\ndotnet_style_prefer_inferred_anonymous_type_member_names         = false:warning\r\ndotnet_style_prefer_inferred_tuple_names                         = false:warning\r\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning\r\ndotnet_style_prefer_simplified_boolean_expressions               = true:suggestion\r\ndotnet_style_prefer_simplified_interpolation                     = true:suggestion\r\n\r\n# Field preferences\r\ndotnet_style_readonly_field = true:warning\r\n\r\n# Parameter preferences\r\ndotnet_code_quality_unused_parameters = all:suggestion\r\n\r\n# Suppression preferences\r\ndotnet_remove_unnecessary_suppression_exclusions = silent\r\n\r\n# New line preferences\r\ndotnet_style_allow_multiple_blank_lines_experimental              = false:warning\r\ndotnet_style_allow_statement_immediately_after_block_experimental = false:warning\r\n\r\n#### C# Coding Conventions ####\r\n[*.cs]\r\n\r\n# var preferences\r\ncsharp_style_var_elsewhere             = true:none\r\ncsharp_style_var_for_built_in_types    = true:none\r\ncsharp_style_var_when_type_is_apparent = true:none\r\n\r\n# Expression-bodied members\r\ncsharp_style_expression_bodied_accessors       = when_on_single_line:suggestion\r\ncsharp_style_expression_bodied_constructors    = false:warning\r\ncsharp_style_expression_bodied_indexers        = false:warning\r\ncsharp_style_expression_bodied_lambdas         = when_on_single_line:suggestion\r\ncsharp_style_expression_bodied_local_functions = false:warning\r\ncsharp_style_expression_bodied_methods         = false:warning\r\ncsharp_style_expression_bodied_operators       = false:warning\r\ncsharp_style_expression_bodied_properties      = false:warning\r\n\r\n# Pattern matching preferences\r\ncsharp_style_pattern_matching_over_as_with_null_check = true:warning\r\ncsharp_style_pattern_matching_over_is_with_cast_check = true:warning\r\ncsharp_style_prefer_not_pattern                       = true:warning\r\ncsharp_style_prefer_pattern_matching                  = true:suggestion\r\ncsharp_style_prefer_switch_expression                 = true:warning\r\n\r\n# Null-checking preferences\r\ncsharp_style_conditional_delegate_call = true:suggestion\r\n\r\n# Modifier preferences\r\ncsharp_prefer_static_local_function = true:warning\r\ncsharp_preferred_modifier_order     = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent\r\n\r\n# Code-block preferences\r\ncsharp_prefer_braces                        = true:warning\r\ncsharp_prefer_simple_using_statement        = true:warning\r\ncsharp_style_prefer_method_group_conversion = true:suggestion\r\ncsharp_style_prefer_top_level_statements    = true:suggestion\r\n\r\n# Expression-level preferences\r\ncsharp_prefer_simple_default_expression                     = true:warning\r\ncsharp_style_deconstructed_variable_declaration             = true:warning\r\ncsharp_style_implicit_object_creation_when_type_is_apparent = true:warning\r\ncsharp_style_inlined_variable_declaration                   = true:warning\r\ncsharp_style_pattern_local_over_anonymous_function          = true:warning\r\ncsharp_style_prefer_index_operator                          = true:warning\r\ncsharp_style_prefer_local_over_anonymous_function           = true:warning\r\ncsharp_style_prefer_null_check_over_type_check              = true:warning\r\ncsharp_style_prefer_range_operator                          = true:warning\r\ncsharp_style_prefer_tuple_swap                              = true:warning\r\ncsharp_style_prefer_utf8_string_literals                    = false:silent\r\ncsharp_style_throw_expression                               = false:warning\r\ncsharp_style_unused_value_assignment_preference             = discard_variable:none\r\ncsharp_style_unused_value_expression_statement_preference   = discard_variable:none\r\n\r\n# 'using' directive preferences\r\ncsharp_using_directive_placement = outside_namespace:warning\r\n\r\n#### C# Formatting Rules ####\r\n\r\n# New line preferences\r\ncsharp_new_line_before_catch                                                      = true\r\ncsharp_new_line_before_else                                                       = true\r\ncsharp_new_line_before_finally                                                    = true\r\ncsharp_new_line_before_members_in_anonymous_types                                 = true\r\ncsharp_new_line_before_members_in_object_initializers                             = true\r\ncsharp_new_line_before_open_brace                                                 = all\r\ncsharp_new_line_between_query_expression_clauses                                  = true\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:warning\r\ncsharp_style_allow_blank_lines_between_consecutive_braces_experimental            = false:warning\r\ncsharp_style_allow_embedded_statements_on_same_line_experimental                  = false:warning\r\n\r\n# Indentation preferences\r\ncsharp_indent_block_contents           = true\r\ncsharp_indent_braces                   = false\r\ncsharp_indent_case_contents            = true\r\ncsharp_indent_case_contents_when_block = false\r\ncsharp_indent_labels                   = one_less_than_current\r\ncsharp_indent_switch_labels            = true\r\n\r\n# Space preferences\r\ncsharp_space_after_cast                                                  = false\r\ncsharp_space_after_colon_in_inheritance_clause                           = true\r\ncsharp_space_after_comma                                                 = true\r\ncsharp_space_after_dot                                                   = false\r\ncsharp_space_after_keywords_in_control_flow_statements                   = true\r\ncsharp_space_after_semicolon_in_for_statement                            = true\r\ncsharp_space_around_binary_operators                                     = before_and_after\r\ncsharp_space_around_declaration_statements                               = false\r\ncsharp_space_before_colon_in_inheritance_clause                          = true\r\ncsharp_space_before_comma                                                = false\r\ncsharp_space_before_dot                                                  = false\r\ncsharp_space_before_open_square_brackets                                 = false\r\ncsharp_space_before_semicolon_in_for_statement                           = false\r\ncsharp_space_between_empty_square_brackets                               = false\r\ncsharp_space_between_method_call_empty_parameter_list_parentheses        = false\r\ncsharp_space_between_method_call_name_and_opening_parenthesis            = false\r\ncsharp_space_between_method_call_parameter_list_parentheses              = false\r\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\r\ncsharp_space_between_method_declaration_name_and_open_parenthesis        = false\r\ncsharp_space_between_method_declaration_parameter_list_parentheses       = false\r\ncsharp_space_between_parentheses                                         = false\r\ncsharp_space_between_square_brackets                                     = false\r\n\r\n# Wrapping preferences\r\ncsharp_preserve_single_line_blocks     = true\r\ncsharp_preserve_single_line_statements = false\r\n\r\n# Namespace preferences\r\ncsharp_style_namespace_declarations = file_scoped:warning\r\ndotnet_style_namespace_match_folder = false\r\n\r\n#### Naming styles ####\r\n[*.{cs,vb}]\r\n\r\n# Naming rules\r\n\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols  = types_and_namespaces\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.severity = warning\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.symbols  = interfaces\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.style    = ipascalcase\r\n\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.symbols  = non_field_members\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.symbols  = constant_fields\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.symbols  = public_fields\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.private_fields_should_be__camelcase.severity = warning\r\ndotnet_naming_rule.private_fields_should_be__camelcase.symbols  = private_fields\r\ndotnet_naming_rule.private_fields_should_be__camelcase.style    = _camelcase\r\n\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = warning\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols  = type_parameters\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.style    = tpascalcase\r\n\r\ndotnet_naming_rule.parameters_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.parameters_should_be_camelcase.symbols  = parameters\r\ndotnet_naming_rule.parameters_should_be_camelcase.style    = camelcase\r\n\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.symbols  = local_constants\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.local_variables_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.local_variables_should_be_camelcase.symbols  = local_variables\r\ndotnet_naming_rule.local_variables_should_be_camelcase.style    = camelcase\r\n\r\ndotnet_naming_rule.local_functions_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.local_functions_should_be_camelcase.symbols  = local_functions\r\ndotnet_naming_rule.local_functions_should_be_camelcase.style    = camelcase\r\n\r\n# Symbol specifications\r\n\r\ndotnet_naming_symbols.types_and_namespaces.applicable_kinds           = namespace, class, struct, interface, enum\r\ndotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.types_and_namespaces.required_modifiers         =\r\n\r\ndotnet_naming_symbols.interfaces.applicable_kinds           = interface\r\ndotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.interfaces.required_modifiers         =\r\n\r\ndotnet_naming_symbols.non_field_members.applicable_kinds           = property, event, delegate, method\r\ndotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.non_field_members.required_modifiers         =\r\n\r\ndotnet_naming_symbols.constant_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.constant_fields.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.constant_fields.required_modifiers         = const\r\n\r\ndotnet_naming_symbols.public_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal\r\ndotnet_naming_symbols.public_fields.required_modifiers         =\r\n\r\ndotnet_naming_symbols.private_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.private_fields.required_modifiers         =\r\n\r\ndotnet_naming_symbols.type_parameters.applicable_kinds           = type_parameter\r\ndotnet_naming_symbols.type_parameters.applicable_accessibilities = *\r\ndotnet_naming_symbols.type_parameters.required_modifiers         =\r\n\r\ndotnet_naming_symbols.parameters.applicable_kinds           = parameter\r\ndotnet_naming_symbols.parameters.applicable_accessibilities = *\r\ndotnet_naming_symbols.parameters.required_modifiers         =\r\n\r\ndotnet_naming_symbols.local_constants.applicable_kinds           = local\r\ndotnet_naming_symbols.local_constants.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_constants.required_modifiers         = const\r\n\r\ndotnet_naming_symbols.local_variables.applicable_kinds           = local\r\ndotnet_naming_symbols.local_variables.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_variables.required_modifiers         =\r\n\r\ndotnet_naming_symbols.local_functions.applicable_kinds           = local_function\r\ndotnet_naming_symbols.local_functions.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_functions.required_modifiers         =\r\n\r\n# Naming styles\r\n\r\ndotnet_naming_style.pascalcase.required_prefix =\r\ndotnet_naming_style.pascalcase.required_suffix =\r\ndotnet_naming_style.pascalcase.word_separator  =\r\ndotnet_naming_style.pascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.ipascalcase.required_prefix = I\r\ndotnet_naming_style.ipascalcase.required_suffix =\r\ndotnet_naming_style.ipascalcase.word_separator  =\r\ndotnet_naming_style.ipascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.tpascalcase.required_prefix = T\r\ndotnet_naming_style.tpascalcase.required_suffix =\r\ndotnet_naming_style.tpascalcase.word_separator  =\r\ndotnet_naming_style.tpascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.camelcase.required_prefix =\r\ndotnet_naming_style.camelcase.required_suffix =\r\ndotnet_naming_style.camelcase.word_separator  =\r\ndotnet_naming_style.camelcase.capitalization  = camel_case\r\n\r\ndotnet_naming_style._camelcase.required_prefix = _\r\ndotnet_naming_style._camelcase.required_suffix =\r\ndotnet_naming_style._camelcase.word_separator  =\r\ndotnet_naming_style._camelcase.capitalization  = camel_case\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.SnapshotTests/Arch.System.SourceGenerator.SnapshotTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n    <PropertyGroup>\r\n        <TargetFramework>net8.0</TargetFramework>\r\n        <ImplicitUsings>enable</ImplicitUsings>\r\n        <Nullable>enable</Nullable>\r\n        <IsPackable>false</IsPackable>\r\n        <LangVersion>latest</LangVersion>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.0\" />\r\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"5.0.0\" />\r\n        <PackageReference Include=\"NUnit\" Version=\"4.3.2\" />\r\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.8.0\">\r\n            <PrivateAssets>all</PrivateAssets>\r\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\r\n        </PackageReference>\r\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.3\">\r\n            <PrivateAssets>all</PrivateAssets>\r\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\r\n        </PackageReference>\r\n    </ItemGroup>\r\n\r\n    <ItemGroup>\r\n        <ProjectReference Include=\"..\\Arch.System.SourceGenerator\\Arch.System.SourceGenerator.csproj\" />\r\n        <ProjectReference Include=\"..\\Arch.System\\Arch.System.csproj\" />\r\n    </ItemGroup>\r\n</Project>\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.SnapshotTests/SnapshotTest.cs",
    "content": "﻿using System.Reflection;\r\nusing System.Runtime.ExceptionServices;\r\nusing Arch.Core;\r\nusing Microsoft.CodeAnalysis;\r\nusing Microsoft.CodeAnalysis.CSharp;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n///     Tests <see cref=\"QueryGenerator\"/> by individually compiling and running each test system from\r\n///     Arch.System.SourceGenerator.TestCompilation.\r\n///     The tests themselves are run in the Arch.System.SourceGenerator.TestCompilation project as well,\r\n///     but here they are run a second time in complete isolation.\r\n///     These tests also ensure that the generated code matches the expected output.\r\n/// </summary>\r\n/// <remarks>\r\n///     For future devs: If you're having trouble with specific test errors, first make sure\r\n///     your system does not use Primary Constructors or Collection Initializers.\r\n/// </remarks>\r\n[TestFixture]\r\ninternal class SnapshotTest\r\n{\r\n    public static string ProjectName { get; } =\r\n        $\"{nameof(Arch)}.{nameof(System)}.{nameof(SourceGenerator)}.Tests\";\r\n\r\n    /// <summary>\r\n    ///     Loads the compilation into memory and tests the specified system.\r\n    /// </summary>\r\n    /// <param name=\"compilation\">The compilation to test.</param>\r\n    /// <param name=\"testSystemName\">The name of the system to test.</param>\r\n    private static void TestSystem(Compilation compilation, string testSystemName)\r\n    {\r\n        // Load the assembly\r\n        using var memory = new MemoryStream();\r\n        compilation.Emit(memory);\r\n        var assembly = Assembly.Load(memory.ToArray());\r\n\r\n        // A system needs a world\r\n        using var world = World.Create();\r\n\r\n        // Find the system type in the assembly\r\n        var systemType = assembly.GetType($\"{ProjectName}.{testSystemName}\");\r\n        Assert.That(systemType, Is.Not.Null, $\"System type {testSystemName} not found in assembly {assembly.FullName}.\");\r\n\r\n        // Create an instance of the system\r\n        var system = Activator.CreateInstance(systemType, new[] { world }) as BaseSystem<World, int>;\r\n        Assert.That(system, Is.Not.Null, $\"Ensure {testSystemName} has a constructor that takes a single World param.\");\r\n\r\n        // Find the Test and Setup methods in the system\r\n        var testMethod = system.GetType().GetMethod(\"Test\", BindingFlags.Public | BindingFlags.Instance);\r\n        Assert.That(testMethod, Is.Not.Null, $\"Method 'Test' not found in system {testSystemName}.\");\r\n        var setupMethod = system.GetType().GetMethod(\"Setup\", BindingFlags.Public | BindingFlags.Instance);\r\n        Assert.That(setupMethod, Is.Not.Null, $\"Method 'Setup' not found in system {testSystemName}.\");\r\n\r\n        try\r\n        {\r\n            // Test the system!\r\n            setupMethod.Invoke(system, []);\r\n            testMethod.Invoke(system, []);\r\n        }\r\n        catch (TargetInvocationException ex)\r\n        {\r\n            // Throw the inner exception for a more useful log\r\n            ExceptionDispatchInfo.Capture(ex.InnerException ?? ex).Throw();\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Verifies the compilation of the specified folder from Arch.System.SourceGenerator.TestCompilation,\r\n    /// and tests the system, if provided.\r\n    /// </summary>\r\n    /// <param name=\"compilationFolder\">The folder containing the compilation files.</param>\r\n    /// <param name=\"testSystemName\">The name of the system to test, or null if the compilation doesn't point to a BaseTestSystem.</param>\r\n    private static void VerifyCompilation(string compilationFolder, string? testSystemName)\r\n    {\r\n        var solutionPath = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory)?.Parent?.Parent?.Parent?.Parent?.FullName;\r\n        Assert.That(solutionPath, Is.Not.Null, \"Could not find project path.\");\r\n\r\n        var projectPath = Path.Combine(solutionPath, ProjectName);\r\n        Assert.That(projectPath, Is.Not.Null, \"Could not find project path.\");\r\n\r\n        var compilationDirectory = new DirectoryInfo(Path.Combine(projectPath, compilationFolder));\r\n        Assert.That(compilationDirectory.Exists, Is.True, $\"Could not find {compilationFolder} compilation directory.\");\r\n\r\n        // Get all .cs files in the compilation directory\r\n        var csFiles = compilationDirectory.GetFiles(\"*.cs\", SearchOption.AllDirectories);\r\n\r\n        // Ensure that the expected files are NOT present,\r\n        // so they don't conflict with the source-generated output.\r\n        var sourceCsFiles = csFiles\r\n            .Where(file => !file.FullName.Contains(\"ExpectedGeneration\"));\r\n        Assert.That(sourceCsFiles, Is.Not.Empty, \"No source files found for compilation.\");\r\n\r\n        // Include shared files in the compilation\r\n        var sharedDirectory = new DirectoryInfo(Path.Combine(projectPath, \"Shared\"));\r\n        sourceCsFiles = sourceCsFiles.Concat(sharedDirectory.GetFiles(\"*.cs\", SearchOption.AllDirectories));\r\n\r\n        // Parse all the source files\r\n        var parseOptions = CSharpParseOptions.Default\r\n            .WithLanguageVersion(LanguageVersion.Latest);\r\n        var sourceTrees = sourceCsFiles\r\n            .Select(file => CSharpSyntaxTree.ParseText(File.ReadAllText(file.FullName), parseOptions));\r\n\r\n        // Get the system assembly references\r\n        var baseAssemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);\r\n        var systemAssemblies = Directory.GetFiles(baseAssemblyPath!)\r\n           .Where(x => !x.EndsWith(\"Native.dll\"))\r\n           .Where(x =>\r\n           {\r\n               var filename = Path.GetFileName(x);\r\n               return filename.StartsWith(\"System\") || (filename is \"mscorlib.dll\" or \"netstandard.dll\");\r\n           });\r\n\r\n        // Get any additional references needed for the compilation\r\n        IEnumerable<string> references = [\r\n            typeof(World).Assembly.Location,\r\n            typeof(Assert).Assembly.Location,\r\n            typeof(QueryAttribute).Assembly.Location,\r\n            typeof(CommunityToolkit.HighPerformance.ArrayExtensions).Assembly.Location\r\n        ];\r\n\r\n        references = references.Concat(systemAssemblies);\r\n\r\n        // Run the compilation with the source trees and references\r\n        var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)\r\n            .WithOptimizationLevel(OptimizationLevel.Release);\r\n        var inputCompilation = CSharpCompilation.Create(compilationFolder, sourceTrees,\r\n            references: references.Select(r => MetadataReference.CreateFromFile(r)),\r\n            options: compilationOptions);\r\n\r\n        // Run the generator\r\n        GeneratorDriver driver = CSharpGeneratorDriver.Create(new QueryGenerator());\r\n        driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);\r\n\r\n        // Check for compilation diagnostics\r\n        var outputDiagnostics = outputCompilation.GetDiagnostics();\r\n        var errors = outputDiagnostics.Where(d => d.Severity == DiagnosticSeverity.Error);\r\n        var warnings = outputDiagnostics.Where(d => d.Severity == DiagnosticSeverity.Warning);\r\n        Assert.Multiple(() =>\r\n        {\r\n            Assert.That(diagnostics, Is.Empty, \"Generator diagnostics should be empty.\" + string.Join(\"\\n\", diagnostics));\r\n            Assert.That(errors, Is.Empty,\r\n                \"Output compilation should not have errors.\\n\" + string.Join(\"\\n\", errors));\r\n            Warn.Unless(warnings, Is.Empty,\r\n                \"Output compilation should not have warnings.\\n\" + string.Join(\"\\n\", warnings));\r\n        });\r\n\r\n        // Compare the generated files with the expected files\r\n        var expectedFiles = csFiles\r\n            .Where(file => file.FullName.Contains(\"ExpectedGeneration\"))\r\n            .Select(file => (Name: file.Name, Text: File.ReadAllText(file.FullName)))\r\n            .OrderBy(x => x.Name).ToArray();\r\n\r\n        var generatedFiles = driver.GetRunResult().GeneratedTrees\r\n            .Select(tree => (Name: Path.GetFileName(tree.FilePath), Text: tree.GetText().ToString()))\r\n            .Where(x => x.Name != \"Attributes.g.cs\") // Skip the attributes file\r\n            .OrderBy(x => x.Name).ToArray();\r\n\r\n        Assert.That(generatedFiles, Is.EqualTo(expectedFiles));\r\n\r\n        // If we're not testing a specific BaseTestSystem, we're done!\r\n        if (testSystemName is not null)\r\n        {\r\n            TestSystem(outputCompilation, testSystemName);\r\n        }\r\n    }\r\n\r\n    [Test]\r\n    public void BasicCompilation()\r\n    {\r\n        VerifyCompilation(nameof(BasicCompilation), \"BasicSystem\");\r\n    }\r\n\r\n    [Test]\r\n    public void AttributeQueryCompilation()\r\n    {\r\n        VerifyCompilation(nameof(AttributeQueryCompilation), \"AttributeQuerySystem\");\r\n    }\r\n\r\n    [Test]\r\n    public void ParamQueryCompilation()\r\n    {\r\n        VerifyCompilation(nameof(ParamQueryCompilation), \"ParamQuerySystem\");\r\n    }\r\n\r\n    [Test]\r\n    public void DataParamCompilation()\r\n    {\r\n        VerifyCompilation(nameof(DataParamCompilation), \"DataParamSystem\");\r\n    }\r\n\r\n    [Test]\r\n    public void GeneratedUpdateCompilation()\r\n    {\r\n        VerifyCompilation(nameof(GeneratedUpdateCompilation), \"GeneratedUpdateSystem\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/.editorconfig",
    "content": "root = true\r\n\r\n# All files\r\n[*]\r\n\r\n# Indentation and spacing\r\nend_of_line              = crlf\r\nindent_style             = space\r\ntrim_trailing_whitespace = true\r\n\r\n# New line preferences\r\nend_of_line          = crlf\r\ninsert_final_newline = true\r\n\r\n# Xml project files\r\n[*.{csproj,proj,projitems,shproj,vbproj,vcxproj,vcxproj.filters}]\r\nindent_size = 2\r\n\r\n# Xml config files\r\n[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]\r\nindent_size = 2\r\n\r\n# Other markup files\r\n[*.{json,xml,yml,yaml}]\r\nindent_size = 2\r\n\r\n# Markdown files\r\n[*.md]\r\nindent_size              = 1\r\ntrim_trailing_whitespace = false\r\n\r\n# C# files\r\n[*.cs]\r\n\r\n#### Core EditorConfig Options ####\r\n\r\nfile_header_template = unset\r\n\r\n# Indentation and spacing\r\nindent_size = 4\r\n\r\n#### .NET Coding Conventions ####\r\n[*.{cs,vb}]\r\n\r\n# Organize usings\r\ndotnet_separate_import_directive_groups = false\r\ndotnet_sort_system_directives_first     = true\r\n\r\n# this. and Me. preferences\r\ndotnet_style_qualification_for_event    = false:warning\r\ndotnet_style_qualification_for_field    = false:warning\r\ndotnet_style_qualification_for_method   = false:warning\r\ndotnet_style_qualification_for_property = false:warning\r\n\r\n# Language keywords vs BCL types preferences\r\ndotnet_style_predefined_type_for_locals_parameters_members = true:warning\r\ndotnet_style_predefined_type_for_member_access             = true:warning\r\n\r\n# Parentheses preferences\r\ndotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning\r\ndotnet_style_parentheses_in_other_binary_operators      = always_for_clarity:warning\r\ndotnet_style_parentheses_in_other_operators             = never_if_unnecessary:warning\r\ndotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning\r\n\r\n# Modifier preferences\r\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:warning\r\n\r\n# Expression-level preferences\r\ndotnet_style_coalesce_expression                                 = true:suggestion\r\ndotnet_style_collection_initializer                              = true:warning\r\ndotnet_style_explicit_tuple_names                                = true:warning\r\ndotnet_style_null_propagation                                    = true:suggestion\r\ndotnet_style_object_initializer                                  = true:warning\r\ndotnet_style_operator_placement_when_wrapping                    = beginning_of_line\r\ndotnet_style_prefer_auto_properties                              = true:warning\r\ndotnet_style_prefer_compound_assignment                          = true:warning\r\ndotnet_style_prefer_conditional_expression_over_assignment       = true:suggestion\r\ndotnet_style_prefer_conditional_expression_over_return           = false:silent\r\ndotnet_style_prefer_foreach_explicit_cast_in_source              = when_strongly_typed\r\ndotnet_style_prefer_inferred_anonymous_type_member_names         = false:warning\r\ndotnet_style_prefer_inferred_tuple_names                         = false:warning\r\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning\r\ndotnet_style_prefer_simplified_boolean_expressions               = true:suggestion\r\ndotnet_style_prefer_simplified_interpolation                     = true:suggestion\r\n\r\n# Field preferences\r\ndotnet_style_readonly_field = true:warning\r\n\r\n# Parameter preferences\r\ndotnet_code_quality_unused_parameters = all:suggestion\r\n\r\n# Suppression preferences\r\ndotnet_remove_unnecessary_suppression_exclusions = silent\r\n\r\n# New line preferences\r\ndotnet_style_allow_multiple_blank_lines_experimental              = false:warning\r\ndotnet_style_allow_statement_immediately_after_block_experimental = false:warning\r\n\r\n#### C# Coding Conventions ####\r\n[*.cs]\r\n\r\n# var preferences\r\ncsharp_style_var_elsewhere             = true:none\r\ncsharp_style_var_for_built_in_types    = true:none\r\ncsharp_style_var_when_type_is_apparent = true:none\r\n\r\n# Expression-bodied members\r\ncsharp_style_expression_bodied_accessors       = when_on_single_line:suggestion\r\ncsharp_style_expression_bodied_constructors    = false:warning\r\ncsharp_style_expression_bodied_indexers        = false:warning\r\ncsharp_style_expression_bodied_lambdas         = when_on_single_line:suggestion\r\ncsharp_style_expression_bodied_local_functions = false:warning\r\ncsharp_style_expression_bodied_methods         = false:warning\r\ncsharp_style_expression_bodied_operators       = false:warning\r\ncsharp_style_expression_bodied_properties      = false:warning\r\n\r\n# Pattern matching preferences\r\ncsharp_style_pattern_matching_over_as_with_null_check = true:warning\r\ncsharp_style_pattern_matching_over_is_with_cast_check = true:warning\r\ncsharp_style_prefer_not_pattern                       = true:warning\r\ncsharp_style_prefer_pattern_matching                  = true:suggestion\r\ncsharp_style_prefer_switch_expression                 = true:warning\r\n\r\n# Null-checking preferences\r\ncsharp_style_conditional_delegate_call = true:suggestion\r\n\r\n# Modifier preferences\r\ncsharp_prefer_static_local_function = true:warning\r\ncsharp_preferred_modifier_order     = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent\r\n\r\n# Code-block preferences\r\ncsharp_prefer_braces                        = true:warning\r\ncsharp_prefer_simple_using_statement        = true:warning\r\ncsharp_style_prefer_method_group_conversion = true:suggestion\r\ncsharp_style_prefer_top_level_statements    = true:suggestion\r\n\r\n# Expression-level preferences\r\ncsharp_prefer_simple_default_expression                     = true:warning\r\ncsharp_style_deconstructed_variable_declaration             = true:warning\r\ncsharp_style_implicit_object_creation_when_type_is_apparent = true:warning\r\ncsharp_style_inlined_variable_declaration                   = true:warning\r\ncsharp_style_pattern_local_over_anonymous_function          = true:warning\r\ncsharp_style_prefer_index_operator                          = true:warning\r\ncsharp_style_prefer_local_over_anonymous_function           = true:warning\r\ncsharp_style_prefer_null_check_over_type_check              = true:warning\r\ncsharp_style_prefer_range_operator                          = true:warning\r\ncsharp_style_prefer_tuple_swap                              = true:warning\r\ncsharp_style_prefer_utf8_string_literals                    = false:silent\r\ncsharp_style_throw_expression                               = false:warning\r\ncsharp_style_unused_value_assignment_preference             = discard_variable:none\r\ncsharp_style_unused_value_expression_statement_preference   = discard_variable:none\r\n\r\n# 'using' directive preferences\r\ncsharp_using_directive_placement = outside_namespace:warning\r\n\r\n#### C# Formatting Rules ####\r\n\r\n# New line preferences\r\ncsharp_new_line_before_catch                                                      = true\r\ncsharp_new_line_before_else                                                       = true\r\ncsharp_new_line_before_finally                                                    = true\r\ncsharp_new_line_before_members_in_anonymous_types                                 = true\r\ncsharp_new_line_before_members_in_object_initializers                             = true\r\ncsharp_new_line_before_open_brace                                                 = all\r\ncsharp_new_line_between_query_expression_clauses                                  = true\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:warning\r\ncsharp_style_allow_blank_lines_between_consecutive_braces_experimental            = false:warning\r\ncsharp_style_allow_embedded_statements_on_same_line_experimental                  = false:warning\r\n\r\n# Indentation preferences\r\ncsharp_indent_block_contents           = true\r\ncsharp_indent_braces                   = false\r\ncsharp_indent_case_contents            = true\r\ncsharp_indent_case_contents_when_block = false\r\ncsharp_indent_labels                   = one_less_than_current\r\ncsharp_indent_switch_labels            = true\r\n\r\n# Space preferences\r\ncsharp_space_after_cast                                                  = false\r\ncsharp_space_after_colon_in_inheritance_clause                           = true\r\ncsharp_space_after_comma                                                 = true\r\ncsharp_space_after_dot                                                   = false\r\ncsharp_space_after_keywords_in_control_flow_statements                   = true\r\ncsharp_space_after_semicolon_in_for_statement                            = true\r\ncsharp_space_around_binary_operators                                     = before_and_after\r\ncsharp_space_around_declaration_statements                               = false\r\ncsharp_space_before_colon_in_inheritance_clause                          = true\r\ncsharp_space_before_comma                                                = false\r\ncsharp_space_before_dot                                                  = false\r\ncsharp_space_before_open_square_brackets                                 = false\r\ncsharp_space_before_semicolon_in_for_statement                           = false\r\ncsharp_space_between_empty_square_brackets                               = false\r\ncsharp_space_between_method_call_empty_parameter_list_parentheses        = false\r\ncsharp_space_between_method_call_name_and_opening_parenthesis            = false\r\ncsharp_space_between_method_call_parameter_list_parentheses              = false\r\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\r\ncsharp_space_between_method_declaration_name_and_open_parenthesis        = false\r\ncsharp_space_between_method_declaration_parameter_list_parentheses       = false\r\ncsharp_space_between_parentheses                                         = false\r\ncsharp_space_between_square_brackets                                     = false\r\n\r\n# Wrapping preferences\r\ncsharp_preserve_single_line_blocks     = true\r\ncsharp_preserve_single_line_statements = false\r\n\r\n# Namespace preferences\r\ncsharp_style_namespace_declarations = file_scoped:warning\r\ndotnet_style_namespace_match_folder = false\r\n\r\n#### Naming styles ####\r\n[*.{cs,vb}]\r\n\r\n# Naming rules\r\n\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols  = types_and_namespaces\r\ndotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.severity = warning\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.symbols  = interfaces\r\ndotnet_naming_rule.interfaces_should_be_ipascalcase.style    = ipascalcase\r\n\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.symbols  = non_field_members\r\ndotnet_naming_rule.non_field_members_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.symbols  = constant_fields\r\ndotnet_naming_rule.constant_fields_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.symbols  = public_fields\r\ndotnet_naming_rule.public_fields_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.private_fields_should_be__camelcase.severity = warning\r\ndotnet_naming_rule.private_fields_should_be__camelcase.symbols  = private_fields\r\ndotnet_naming_rule.private_fields_should_be__camelcase.style    = _camelcase\r\n\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = warning\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols  = type_parameters\r\ndotnet_naming_rule.type_parameters_should_be_tpascalcase.style    = tpascalcase\r\n\r\ndotnet_naming_rule.parameters_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.parameters_should_be_camelcase.symbols  = parameters\r\ndotnet_naming_rule.parameters_should_be_camelcase.style    = camelcase\r\n\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.severity = warning\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.symbols  = local_constants\r\ndotnet_naming_rule.local_constants_should_be_pascalcase.style    = pascalcase\r\n\r\ndotnet_naming_rule.local_variables_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.local_variables_should_be_camelcase.symbols  = local_variables\r\ndotnet_naming_rule.local_variables_should_be_camelcase.style    = camelcase\r\n\r\ndotnet_naming_rule.local_functions_should_be_camelcase.severity = warning\r\ndotnet_naming_rule.local_functions_should_be_camelcase.symbols  = local_functions\r\ndotnet_naming_rule.local_functions_should_be_camelcase.style    = camelcase\r\n\r\n# Symbol specifications\r\n\r\ndotnet_naming_symbols.types_and_namespaces.applicable_kinds           = namespace, class, struct, interface, enum\r\ndotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.types_and_namespaces.required_modifiers         =\r\n\r\ndotnet_naming_symbols.interfaces.applicable_kinds           = interface\r\ndotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.interfaces.required_modifiers         =\r\n\r\ndotnet_naming_symbols.non_field_members.applicable_kinds           = property, event, delegate, method\r\ndotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.non_field_members.required_modifiers         =\r\n\r\ndotnet_naming_symbols.constant_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.constant_fields.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.constant_fields.required_modifiers         = const\r\n\r\ndotnet_naming_symbols.public_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal\r\ndotnet_naming_symbols.public_fields.required_modifiers         =\r\n\r\ndotnet_naming_symbols.private_fields.applicable_kinds           = field\r\ndotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected\r\ndotnet_naming_symbols.private_fields.required_modifiers         =\r\n\r\ndotnet_naming_symbols.type_parameters.applicable_kinds           = type_parameter\r\ndotnet_naming_symbols.type_parameters.applicable_accessibilities = *\r\ndotnet_naming_symbols.type_parameters.required_modifiers         =\r\n\r\ndotnet_naming_symbols.parameters.applicable_kinds           = parameter\r\ndotnet_naming_symbols.parameters.applicable_accessibilities = *\r\ndotnet_naming_symbols.parameters.required_modifiers         =\r\n\r\ndotnet_naming_symbols.local_constants.applicable_kinds           = local\r\ndotnet_naming_symbols.local_constants.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_constants.required_modifiers         = const\r\n\r\ndotnet_naming_symbols.local_variables.applicable_kinds           = local\r\ndotnet_naming_symbols.local_variables.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_variables.required_modifiers         =\r\n\r\ndotnet_naming_symbols.local_functions.applicable_kinds           = local_function\r\ndotnet_naming_symbols.local_functions.applicable_accessibilities = local\r\ndotnet_naming_symbols.local_functions.required_modifiers         =\r\n\r\n# Naming styles\r\n\r\ndotnet_naming_style.pascalcase.required_prefix =\r\ndotnet_naming_style.pascalcase.required_suffix =\r\ndotnet_naming_style.pascalcase.word_separator  =\r\ndotnet_naming_style.pascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.ipascalcase.required_prefix = I\r\ndotnet_naming_style.ipascalcase.required_suffix =\r\ndotnet_naming_style.ipascalcase.word_separator  =\r\ndotnet_naming_style.ipascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.tpascalcase.required_prefix = T\r\ndotnet_naming_style.tpascalcase.required_suffix =\r\ndotnet_naming_style.tpascalcase.word_separator  =\r\ndotnet_naming_style.tpascalcase.capitalization  = pascal_case\r\n\r\ndotnet_naming_style.camelcase.required_prefix =\r\ndotnet_naming_style.camelcase.required_suffix =\r\ndotnet_naming_style.camelcase.word_separator  =\r\ndotnet_naming_style.camelcase.capitalization  = camel_case\r\n\r\ndotnet_naming_style._camelcase.required_prefix = _\r\ndotnet_naming_style._camelcase.required_suffix =\r\ndotnet_naming_style._camelcase.word_separator  =\r\ndotnet_naming_style._camelcase.capitalization  = camel_case\r\n\r\n# Primary constructors don't work with manual compilation of C#\r\ncsharp_style_prefer_primary_constructors = false\r\n\r\n# Collection expressions don't work with manual compilation of C#\r\ndotnet_diagnostic.IDE0301.severity = none\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/.gitignore",
    "content": "Generated/\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/Arch.System.SourceGenerator.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\r\n    <PropertyGroup>\r\n        <TargetFramework>net8.0</TargetFramework>\r\n        <Nullable>enable</Nullable>\r\n    </PropertyGroup>\r\n\r\n    <ItemGroup>\r\n        <PackageReference Include=\"Arch\" Version=\"2.1.0\" />\r\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.0\" />\r\n        <PackageReference Include=\"NUnit\" Version=\"4.3.2\" />\r\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"5.0.0\">\r\n            <TreatAsUsed>true</TreatAsUsed>\r\n        </PackageReference>\r\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.8.0\">\r\n            <PrivateAssets>all</PrivateAssets>\r\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\r\n        </PackageReference>\r\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.3\">\r\n            <PrivateAssets>all</PrivateAssets>\r\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\r\n        </PackageReference>\r\n    </ItemGroup>\r\n  \r\n    <ItemGroup>\r\n        <ProjectReference Include=\"..\\Arch.System.SourceGenerator\\Arch.System.SourceGenerator.csproj\" OutputItemType=\"Analyzer\" ReferenceOutputAssembly=\"false\" />\r\n        <ProjectReference Include=\"..\\Arch.System\\Arch.System.csproj\" />\r\n    </ItemGroup>\r\n\r\n    <!-- Emit compiler generated files to Generated/ so that developers can easily find them, and copy them to ExpectedGeneration folders as needed -->\r\n    <PropertyGroup>\r\n        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>\r\n        <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>\r\n    </PropertyGroup>\r\n\r\n    <!-- Remove any bad .cs files that we don't want to include in the compilation -->\r\n    <ItemGroup>\r\n        <Compile Remove=\"Generated\\**\\*\" />\r\n        <Compile Remove=\"**\\ExpectedGeneration\\**\\*\" />\r\n    </ItemGroup>\r\n\r\n    <!-- Include removed stuff in the Solution Explorer -->\r\n    <ItemGroup>\r\n        <None Include=\"Generated\\**\\*\" />\r\n        <None Include=\"**\\ExpectedGeneration\\**\\*\" />\r\n    </ItemGroup>\r\n</Project>\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/AttributeQuerySystem.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Tests queries with different attribute combinations.\r\n/// </summary>\r\ninternal partial class AttributeQuerySystem : BaseTestSystem\r\n{\r\n    public AttributeQuerySystem(World world) : base(world) { }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public void IncrementA(Entity e)\r\n    {\r\n        ref var a = ref World.Get<IntComponentA>(e);\r\n        a.Value++;\r\n    }\r\n\r\n    [Query]\r\n    [Any(typeof(IntComponentA), typeof(IntComponentB))]\r\n    public void IncrementAOrB(Entity e)\r\n    {\r\n        ref var a = ref World.TryGetRef<IntComponentA>(e, out bool aExists);\r\n        ref var b = ref World.TryGetRef<IntComponentB>(e, out bool bExists);\r\n\r\n        if (aExists)\r\n        {\r\n            a.Value++;\r\n        }\r\n\r\n        if (bExists)\r\n        {\r\n            b.Value++;\r\n        }\r\n    }\r\n\r\n    [Query]\r\n    [Any(typeof(IntComponentA), typeof(IntComponentB))]\r\n    [None(typeof(IntComponentC))]\r\n    public void IncrementAOrBNotC(Entity e)\r\n    {\r\n        ref var a = ref World.TryGetRef<IntComponentA>(e, out bool aExists);\r\n        ref var b = ref World.TryGetRef<IntComponentB>(e, out bool bExists);\r\n\r\n        if (aExists)\r\n        {\r\n            a.Value++;\r\n        }\r\n\r\n        if (bExists)\r\n        {\r\n            b.Value++;\r\n        }\r\n    }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA), typeof(IntComponentB))]\r\n    public void IncrementAAndB(Entity e)\r\n    {\r\n        ref var a = ref World.Get<IntComponentA>(e);\r\n        a.Value++;\r\n        ref var b = ref World.Get<IntComponentB>(e);\r\n        b.Value++;\r\n    }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    [None(typeof(IntComponentB))]\r\n    public void IncrementANotB(Entity e)\r\n    {\r\n        ref var a = ref World.Get<IntComponentA>(e);\r\n        a.Value++;\r\n    }\r\n\r\n    [Query]\r\n    [Exclusive(typeof(IntComponentA), typeof(IntComponentB))]\r\n    public void IncrementAAndBExclusive(Entity e)\r\n    {\r\n        ref var a = ref World.Get<IntComponentA>(e);\r\n        a.Value++;\r\n        ref var b = ref World.Get<IntComponentB>(e);\r\n        b.Value++;\r\n    }\r\n\r\n    private (Entity Entity, Dictionary<Type, int> ComponentValues)[]\r\n        _expectedComponentValues = Array.Empty<(Entity, Dictionary<Type, int>)>();\r\n\r\n    public override void Setup()\r\n    {\r\n        _expectedComponentValues = new []\r\n        {\r\n            (World.Create(new IntComponentA()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 } }),\r\n            (World.Create(new IntComponentB()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentB), 0 } }),\r\n            (World.Create(new IntComponentA(), new IntComponentB()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 } }),\r\n            (World.Create(new IntComponentA(), new IntComponentB(), new IntComponentC()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 }, { typeof(IntComponentC), 0 } })\r\n        };\r\n    }\r\n\r\n    private void TestExpectedValues()\r\n    {\r\n        foreach (var (e, values) in _expectedComponentValues)\r\n        {\r\n            foreach (var (type, expectedValue) in values)\r\n            {\r\n                var component = World.Get(e, type) as IIntComponent;\r\n                Assert.That(component, Is.Not.Null);\r\n                Assert.That(component.Value, Is.EqualTo(expectedValue));\r\n            }\r\n        }\r\n    }\r\n\r\n    public override void Update(in int t)\r\n    {\r\n        TestExpectedValues();\r\n\r\n        IncrementAQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementAOrBQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[1].ComponentValues[typeof(IntComponentB)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementAOrBNotCQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[1].ComponentValues[typeof(IntComponentB)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementAAndBQuery(World);\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementANotBQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementAAndBExclusiveQuery(World);\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;\r\n        TestExpectedValues();\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementA(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _IncrementA_Initialized;\r\n        private Query? _IncrementA_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementAQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementA_Initialized, world))\r\n            {\r\n                _IncrementA_Query = world.Query(in IncrementA_QueryDescription);\r\n                _IncrementA_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementA_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementA(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAAndB(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementAAndB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _IncrementAAndB_Initialized;\r\n        private Query? _IncrementAAndB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementAAndBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementAAndB_Initialized, world))\r\n            {\r\n                _IncrementAAndB_Query = world.Query(in IncrementAAndB_QueryDescription);\r\n                _IncrementAAndB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementAAndB_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementAAndB(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAAndBExclusive(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementAAndBExclusive_QueryDescription = new QueryDescription(all: Signature.Null, any: Signature.Null, none: Signature.Null, exclusive: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)));\r\n        private World? _IncrementAAndBExclusive_Initialized;\r\n        private Query? _IncrementAAndBExclusive_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementAAndBExclusiveQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementAAndBExclusive_Initialized, world))\r\n            {\r\n                _IncrementAAndBExclusive_Query = world.Query(in IncrementAAndBExclusive_QueryDescription);\r\n                _IncrementAAndBExclusive_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementAAndBExclusive_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementAAndBExclusive(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementANotB(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementANotB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), exclusive: Signature.Null);\r\n        private World? _IncrementANotB_Initialized;\r\n        private Query? _IncrementANotB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementANotBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementANotB_Initialized, world))\r\n            {\r\n                _IncrementANotB_Query = world.Query(in IncrementANotB_QueryDescription);\r\n                _IncrementANotB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementANotB_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementANotB(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAOrB(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementAOrB_QueryDescription = new QueryDescription(all: Signature.Null, any: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _IncrementAOrB_Initialized;\r\n        private Query? _IncrementAOrB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementAOrBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementAOrB_Initialized, world))\r\n            {\r\n                _IncrementAOrB_Query = world.Query(in IncrementAOrB_QueryDescription);\r\n                _IncrementAOrB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementAOrB_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementAOrB(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAOrBNotC(Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class AttributeQuerySystem\r\n    {\r\n        private QueryDescription IncrementAOrBNotC_QueryDescription = new QueryDescription(all: Signature.Null, any: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentC)), exclusive: Signature.Null);\r\n        private World? _IncrementAOrBNotC_Initialized;\r\n        private Query? _IncrementAOrBNotC_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void IncrementAOrBNotCQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementAOrBNotC_Initialized, world))\r\n            {\r\n                _IncrementAOrBNotC_Query = world.Query(in IncrementAOrBNotC_QueryDescription);\r\n                _IncrementAOrBNotC_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementAOrBNotC_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    IncrementAOrBNotC(@e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/BasicCompilation/BasicSystem.cs",
    "content": "﻿using Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Tests basic query functionality.\r\n/// </summary>\r\ninternal partial class BasicSystem : BaseTestSystem\r\n{\r\n    public BasicSystem(World world) : base(world) { }\r\n\r\n    private int _number = 0;\r\n    static private int _numberStatic = 0;\r\n\r\n    [Query]\r\n    public void Basic(IntComponentA _)\r\n    {\r\n        _number++;\r\n        _numberStatic++;\r\n    }\r\n\r\n    [Query]\r\n    public static void BasicStatic(IntComponentA _)\r\n    {\r\n        _numberStatic++;\r\n    }\r\n\r\n    public override void Setup()\r\n    {\r\n        World.Create(new IntComponentA());\r\n    }\r\n\r\n    public override void Update(in int t)\r\n    {\r\n        Assert.That(_number, Is.EqualTo(0));\r\n        Assert.That(_numberStatic, Is.EqualTo(0));\r\n        BasicQuery(World);\r\n        Assert.That(_number, Is.EqualTo(1));\r\n        Assert.That(_numberStatic, Is.EqualTo(1));\r\n        BasicStaticQuery(World);\r\n        Assert.That(_number, Is.EqualTo(1));\r\n        Assert.That(_numberStatic, Is.EqualTo(2));\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/BasicCompilation/ExpectedGeneration/BasicSystem.Basic(IntComponentA).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class BasicSystem\r\n    {\r\n        private QueryDescription Basic_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _Basic_Initialized;\r\n        private Query? _Basic_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void BasicQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_Basic_Initialized, world))\r\n            {\r\n                _Basic_Query = world.Query(in Basic_QueryDescription);\r\n                _Basic_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _Basic_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    Basic(@_);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/BasicCompilation/ExpectedGeneration/BasicSystem.BasicStatic(IntComponentA).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class BasicSystem\r\n    {\r\n        private static QueryDescription BasicStatic_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _BasicStatic_Initialized;\r\n        private static Query? _BasicStatic_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void BasicStaticQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_BasicStatic_Initialized, world))\r\n            {\r\n                _BasicStatic_Query = world.Query(in BasicStatic_QueryDescription);\r\n                _BasicStatic_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _BasicStatic_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    BasicStatic(@_);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/DataParamSystem.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\r\nusing Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Tests queries using data parameters.\r\n/// </summary>\r\n[SuppressMessage(\"Style\", \"IDE0060:Remove unused parameter\", Justification = \"Allow unused params for query headers\")]\r\ninternal partial class DataParamSystem : BaseTestSystem\r\n{\r\n    public DataParamSystem(World world) : base(world) { }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public static void CountANoParams([Data] ref int count)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountAWithParamsLeft([Data] ref int count, in IntComponentA _)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountAWithParamsRight(in IntComponentA _, [Data] ref int count)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountAWithParamsMiddle(in IntComponentA _, [Data] ref int count, in IntComponentB __)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountATwiceWithParams([Data] ref int count1, in IntComponentA _, [Data] ref int count2, in IntComponentB __)\r\n    {\r\n        count1++;\r\n        count2++;\r\n    }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public static void CountAWithEntityRight(in Entity e, [Data] ref int count)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public static void CountAWithEntityLeft([Data] ref int count, in Entity e)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountAWithEntityAndParamLeft([Data] ref int count, in IntComponentA a, in Entity e)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    [Query]\r\n    public static void CountAWithEntityAndParamRight(in Entity e, in IntComponentA a, [Data] ref int count)\r\n    {\r\n        count++;\r\n    }\r\n\r\n    // compilation fails from https://github.com/genaray/Arch.Extended/issues/89\r\n    //[Query]\r\n    //public void AssignEntityDataParamRight(in IntComponentA a, [Data] ref Entity outEntity)\r\n    //{\r\n    //    outEntity = _sampleEntity;\r\n    //}\r\n\r\n    // compilation fails from https://github.com/genaray/Arch.Extended/issues/89\r\n    //[Query]\r\n    //public void AssignEntityDataParamLeft([Data] ref Entity outEntity, in IntComponentA a)\r\n    //{\r\n    //    outEntity = _sampleEntity;\r\n    //}\r\n\r\n    [Query]\r\n    public static void AssignEntityDataParamWithEntityRight(in Entity e, in IntComponentA a, [Data] ref Entity outEntity)\r\n    {\r\n        outEntity = e;\r\n    }\r\n\r\n    // compilation fails from https://github.com/genaray/Arch.Extended/issues/89\r\n    //[Query]\r\n    //public static void AssignEntityDataParamWithEntityLeft([Data] ref Entity outEntity, in Entity e, in IntComponentA a)\r\n    //{\r\n    //    outEntity = e;\r\n    //}\r\n\r\n    // Crashes source generator due to ? in filename; see https://github.com/genaray/Arch.Extended/issues/91\r\n    //[Query]\r\n    //[All(typeof(IntComponentA))]\r\n    //public static void CountANullable([Data] ref int? count)\r\n    //{\r\n    //    count ??= 0;\r\n    //    count++;\r\n    //}\r\n\r\n    private Entity _sampleEntity;\r\n    public override void Setup()\r\n    {\r\n        _sampleEntity = World.Create(new IntComponentA(), new IntComponentB());\r\n        World.Create(new IntComponentA(), new IntComponentB());\r\n    }\r\n\r\n    public override void Update(in int t)\r\n    {\r\n        int i = 0;\r\n        CountANoParamsQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithParamsLeftQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithParamsRightQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithParamsMiddleQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        int i2 = 0;\r\n        CountATwiceWithParamsQuery(World, ref i, ref i2);\r\n        Assert.Multiple(() =>\r\n        {\r\n            Assert.That(i, Is.EqualTo(2));\r\n            Assert.That(i2, Is.EqualTo(2));\r\n        });\r\n\r\n        i = 0;\r\n        CountAWithEntityRightQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithEntityLeftQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithEntityAndParamLeftQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        i = 0;\r\n        CountAWithEntityAndParamRightQuery(World, ref i);\r\n        Assert.That(i, Is.EqualTo(2));\r\n\r\n        Entity outEntity = Entity.Null;\r\n        //AssignEntityDataParamRightQuery(World, ref outEntity);\r\n        //Assert.That(outEntity, Is.EqualTo(_sampleEntity));\r\n\r\n        //outEntity = Entity.Null;\r\n        //AssignEntityDataParamLeftQuery(World, ref outEntity);\r\n        //Assert.That(outEntity, Is.EqualTo(_sampleEntity));\r\n\r\n        outEntity = Entity.Null;\r\n        AssignEntityDataParamWithEntityRightQuery(World, ref outEntity);\r\n        Assert.That(outEntity, Is.Not.EqualTo(Entity.Null));\r\n\r\n        //outEntity = Entity.Null;\r\n        //AssignEntityDataParamWithEntityLeftQuery(World, ref outEntity);\r\n        //Assert.That(outEntity, Is.Not.EqualTo(Entity.Null));\r\n\r\n        //int? i3 = null;\r\n        //CountANullableQuery(World, ref i3);\r\n        //Assert.That(i, Is.EqualTo(2));\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.AssignEntityDataParamWithEntityRight(in Entity, in IntComponentA, ref Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription AssignEntityDataParamWithEntityRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _AssignEntityDataParamWithEntityRight_Initialized;\r\n        private static Query? _AssignEntityDataParamWithEntityRight_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void AssignEntityDataParamWithEntityRightQuery(World world, ref Arch.Core.Entity @outentity)\r\n        {\r\n            if (!ReferenceEquals(_AssignEntityDataParamWithEntityRight_Initialized, world))\r\n            {\r\n                _AssignEntityDataParamWithEntityRight_Query = world.Query(in AssignEntityDataParamWithEntityRight_QueryDescription);\r\n                _AssignEntityDataParamWithEntityRight_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _AssignEntityDataParamWithEntityRight_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    AssignEntityDataParamWithEntityRight(in @e, in @a, ref @outentity);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountANoParams(ref int).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountANoParams_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountANoParams_Initialized;\r\n        private static Query? _CountANoParams_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountANoParamsQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountANoParams_Initialized, world))\r\n            {\r\n                _CountANoParams_Query = world.Query(in CountANoParams_QueryDescription);\r\n                _CountANoParams_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountANoParams_Query!)\r\n            {\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    CountANoParams(ref @count);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountATwiceWithParams(ref int, in IntComponentA, ref int, in IntComponentB).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountATwiceWithParams_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountATwiceWithParams_Initialized;\r\n        private static Query? _CountATwiceWithParams_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountATwiceWithParamsQuery(World world, ref int @count1, ref int @count2)\r\n        {\r\n            if (!ReferenceEquals(_CountATwiceWithParams_Initialized, world))\r\n            {\r\n                _CountATwiceWithParams_Query = world.Query(in CountATwiceWithParams_QueryDescription);\r\n                _CountATwiceWithParams_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountATwiceWithParams_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                ref var @intcomponentbFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentB>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    ref var @__ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);\r\n                    CountATwiceWithParams(ref @count1, in @_, ref @count2, in @__);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityAndParamLeft(ref int, in IntComponentA, in Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithEntityAndParamLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithEntityAndParamLeft_Initialized;\r\n        private static Query? _CountAWithEntityAndParamLeft_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithEntityAndParamLeftQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithEntityAndParamLeft_Initialized, world))\r\n            {\r\n                _CountAWithEntityAndParamLeft_Query = world.Query(in CountAWithEntityAndParamLeft_QueryDescription);\r\n                _CountAWithEntityAndParamLeft_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithEntityAndParamLeft_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    CountAWithEntityAndParamLeft(ref @count, in @a, in @e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityAndParamRight(in Entity, in IntComponentA, ref int).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithEntityAndParamRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithEntityAndParamRight_Initialized;\r\n        private static Query? _CountAWithEntityAndParamRight_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithEntityAndParamRightQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithEntityAndParamRight_Initialized, world))\r\n            {\r\n                _CountAWithEntityAndParamRight_Query = world.Query(in CountAWithEntityAndParamRight_QueryDescription);\r\n                _CountAWithEntityAndParamRight_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithEntityAndParamRight_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    CountAWithEntityAndParamRight(in @e, in @a, ref @count);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityLeft(ref int, in Entity).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithEntityLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithEntityLeft_Initialized;\r\n        private static Query? _CountAWithEntityLeft_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithEntityLeftQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithEntityLeft_Initialized, world))\r\n            {\r\n                _CountAWithEntityLeft_Query = world.Query(in CountAWithEntityLeft_QueryDescription);\r\n                _CountAWithEntityLeft_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithEntityLeft_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    CountAWithEntityLeft(ref @count, in @e);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityRight(in Entity, ref int).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithEntityRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithEntityRight_Initialized;\r\n        private static Query? _CountAWithEntityRight_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithEntityRightQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithEntityRight_Initialized, world))\r\n            {\r\n                _CountAWithEntityRight_Query = world.Query(in CountAWithEntityRight_QueryDescription);\r\n                _CountAWithEntityRight_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithEntityRight_Query!)\r\n            {\r\n                ref var entityFirstElement = ref chunk.Entity(0);\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);\r\n                    CountAWithEntityRight(in @e, ref @count);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsLeft(ref int, in IntComponentA).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithParamsLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithParamsLeft_Initialized;\r\n        private static Query? _CountAWithParamsLeft_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithParamsLeftQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithParamsLeft_Initialized, world))\r\n            {\r\n                _CountAWithParamsLeft_Query = world.Query(in CountAWithParamsLeft_QueryDescription);\r\n                _CountAWithParamsLeft_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithParamsLeft_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    CountAWithParamsLeft(ref @count, in @_);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsMiddle(in IntComponentA, ref int, in IntComponentB).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithParamsMiddle_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithParamsMiddle_Initialized;\r\n        private static Query? _CountAWithParamsMiddle_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithParamsMiddleQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithParamsMiddle_Initialized, world))\r\n            {\r\n                _CountAWithParamsMiddle_Query = world.Query(in CountAWithParamsMiddle_QueryDescription);\r\n                _CountAWithParamsMiddle_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithParamsMiddle_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                ref var @intcomponentbFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentB>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    ref var @__ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);\r\n                    CountAWithParamsMiddle(in @_, ref @count, in @__);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsRight(in IntComponentA, ref int).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class DataParamSystem\r\n    {\r\n        private static QueryDescription CountAWithParamsRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _CountAWithParamsRight_Initialized;\r\n        private static Query? _CountAWithParamsRight_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void CountAWithParamsRightQuery(World world, ref int @count)\r\n        {\r\n            if (!ReferenceEquals(_CountAWithParamsRight_Initialized, world))\r\n            {\r\n                _CountAWithParamsRight_Query = world.Query(in CountAWithParamsRight_QueryDescription);\r\n                _CountAWithParamsRight_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _CountAWithParamsRight_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    CountAWithParamsRight(in @_, ref @count);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.AutoRunA().g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class GeneratedUpdateSystem\r\n    {\r\n        private QueryDescription AutoRunA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _AutoRunA_Initialized;\r\n        private Query? _AutoRunA_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void AutoRunAQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_AutoRunA_Initialized, world))\r\n            {\r\n                _AutoRunA_Query = world.Query(in AutoRunA_QueryDescription);\r\n                _AutoRunA_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _AutoRunA_Query!)\r\n            {\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    AutoRunA();\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.AutoRunB().g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class GeneratedUpdateSystem\r\n    {\r\n        private QueryDescription AutoRunB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private World? _AutoRunB_Initialized;\r\n        private Query? _AutoRunB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public void AutoRunBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_AutoRunB_Initialized, world))\r\n            {\r\n                _AutoRunB_Query = world.Query(in AutoRunB_QueryDescription);\r\n                _AutoRunB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _AutoRunB_Query!)\r\n            {\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    AutoRunB();\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.g.cs",
    "content": "﻿using System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing System;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class GeneratedUpdateSystem\r\n    {\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public override void Update(in int data)\r\n        {\r\n            AutoRunAQuery(World);\r\n            AutoRunBQuery(World);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/GeneratedUpdateSystem.cs",
    "content": "﻿using Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Tests the auto-generated <see cref=\"Update(in int)\"/> method.\r\n/// </summary>\r\ninternal partial class GeneratedUpdateSystem : BaseTestSystem\r\n{\r\n    public GeneratedUpdateSystem(World world) : base(world) { }\r\n\r\n    private int _number = 0;\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public void AutoRunA()\r\n    {\r\n        Assert.That(_number, Is.EqualTo(0));\r\n        _number++;\r\n    }\r\n\r\n    [Query]\r\n    [All(typeof(IntComponentA))]\r\n    public void AutoRunB()\r\n    {\r\n        Assert.That(_number, Is.EqualTo(1));\r\n        _number++;\r\n    }\r\n\r\n    public override void Setup()\r\n    {\r\n        World.Create(new IntComponentA());\r\n    }\r\n\r\n    public override void Test()\r\n    {\r\n        base.Test();\r\n        Assert.That(_number, Is.EqualTo(2));\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementA(ref IntComponentA).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class ParamQuerySystem\r\n    {\r\n        private static QueryDescription IncrementA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _IncrementA_Initialized;\r\n        private static Query? _IncrementA_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void IncrementAQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementA_Initialized, world))\r\n            {\r\n                _IncrementA_Query = world.Query(in IncrementA_QueryDescription);\r\n                _IncrementA_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementA_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    IncrementA(ref @a);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementAAndB(ref IntComponentA, ref IntComponentB).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class ParamQuerySystem\r\n    {\r\n        private static QueryDescription IncrementAAndB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _IncrementAAndB_Initialized;\r\n        private static Query? _IncrementAAndB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void IncrementAAndBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementAAndB_Initialized, world))\r\n            {\r\n                _IncrementAAndB_Query = world.Query(in IncrementAAndB_QueryDescription);\r\n                _IncrementAAndB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementAAndB_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                ref var @intcomponentbFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentB>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    ref var @b = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);\r\n                    IncrementAAndB(ref @a, ref @b);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementANotC(ref IntComponentA).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class ParamQuerySystem\r\n    {\r\n        private static QueryDescription IncrementANotC_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentC)), exclusive: Signature.Null);\r\n        private static World? _IncrementANotC_Initialized;\r\n        private static Query? _IncrementANotC_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void IncrementANotCQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementANotC_Initialized, world))\r\n            {\r\n                _IncrementANotC_Query = world.Query(in IncrementANotC_QueryDescription);\r\n                _IncrementANotC_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementANotC_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    IncrementANotC(ref @a);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementOnlyAWithB(ref IntComponentA, in IntComponentB).g.cs",
    "content": "﻿#nullable enable\r\nusing System;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing Arch.Core;\r\nusing Arch.Core.Extensions;\r\nusing Arch.Core.Utils;\r\nusing ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;\r\nusing Component = Arch.Core.Component;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests\r\n{\r\n    partial class ParamQuerySystem\r\n    {\r\n        private static QueryDescription IncrementOnlyAWithB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);\r\n        private static World? _IncrementOnlyAWithB_Initialized;\r\n        private static Query? _IncrementOnlyAWithB_Query;\r\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r\n        public static void IncrementOnlyAWithBQuery(World world)\r\n        {\r\n            if (!ReferenceEquals(_IncrementOnlyAWithB_Initialized, world))\r\n            {\r\n                _IncrementOnlyAWithB_Query = world.Query(in IncrementOnlyAWithB_QueryDescription);\r\n                _IncrementOnlyAWithB_Initialized = world;\r\n            }\r\n\r\n            foreach (ref var chunk in _IncrementOnlyAWithB_Query!)\r\n            {\r\n                ref var @intcomponentaFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentA>();\r\n                ref var @intcomponentbFirstElement = ref chunk.GetFirst<global::Arch.System.SourceGenerator.Tests.IntComponentB>();\r\n                foreach (var entityIndex in chunk)\r\n                {\r\n                    ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);\r\n                    ref var @_ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);\r\n                    IncrementOnlyAWithB(ref @a, in @_);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ParamQuerySystem.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Tests queries using parameters.\r\n/// </summary>\r\ninternal partial class ParamQuerySystem : BaseTestSystem\r\n{\r\n    public ParamQuerySystem(World world) : base(world) { }\r\n\r\n    [Query]\r\n    public static void IncrementA(ref IntComponentA a)\r\n    {\r\n        a.Value++;\r\n    }\r\n\r\n    [Query]\r\n    public static void IncrementOnlyAWithB(ref IntComponentA a, in IntComponentB _)\r\n    {\r\n        a.Value++;\r\n    }\r\n\r\n    [Query]\r\n    [None(typeof(IntComponentC))]\r\n    public static void IncrementANotC(ref IntComponentA a)\r\n    {\r\n        a.Value++;\r\n    }\r\n\r\n    [Query]\r\n    public static void IncrementAAndB(ref IntComponentA a, ref IntComponentB b)\r\n    {\r\n        a.Value++;\r\n        b.Value++;\r\n    }\r\n\r\n    private (Entity, Dictionary<Type, int> ComponentValues)[] _expectedComponentValues\r\n        = Array.Empty<(Entity, Dictionary<Type, int> ComponentValues)>();\r\n\r\n    public override void Setup()\r\n    {\r\n        _expectedComponentValues = new[]\r\n        {\r\n            (World.Create(new IntComponentA()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 } }),\r\n            (World.Create(new IntComponentB()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentB), 0 } }),\r\n            (World.Create(new IntComponentA(), new IntComponentB()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 } }),\r\n            (World.Create(new IntComponentA(), new IntComponentB(), new IntComponentC()),\r\n                new Dictionary<Type, int> { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 }, { typeof(IntComponentC), 0 } })\r\n        };\r\n    }\r\n\r\n    private void TestExpectedValues()\r\n    {\r\n        foreach (var (e, values) in _expectedComponentValues)\r\n        {\r\n            foreach (var (type, expectedValue) in values)\r\n            {\r\n                var component = World.Get(e, type) as IIntComponent;\r\n                Assert.That(component, Is.Not.Null);\r\n                Assert.That(component.Value, Is.EqualTo(expectedValue));\r\n            }\r\n        }\r\n    }\r\n\r\n    public override void Update(in int t)\r\n    {\r\n        TestExpectedValues();\r\n\r\n        IncrementAQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementOnlyAWithBQuery(World);\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementANotCQuery(World);\r\n        _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        TestExpectedValues();\r\n\r\n        IncrementAAndBQuery(World);\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;\r\n        _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;\r\n        TestExpectedValues();\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/Shared/BaseTestSystem.cs",
    "content": "﻿using Arch.Core;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n/// Provides a base class for test systems. This must be included in the compilation to ensure that the system is generated correctly.\r\n/// </summary>\r\n/// <param name=\"world\">The world instance to which the system will be attached.</param>\r\ninternal abstract class BaseTestSystem : BaseSystem<World, int>\r\n{\r\n    protected BaseTestSystem(World world) : base(world) { }\r\n\r\n    /// <summary>\r\n    /// Sets up the system for testing. Create entities, components, and any other necessary state.\r\n    /// </summary>\r\n    public abstract void Setup();\r\n\r\n    /// <summary>\r\n    /// Runs the test logic for the system. By default, it simply calls the update pipeline.\r\n    /// </summary>\r\n    public virtual void Test()\r\n    {\r\n        BeforeUpdate(0);\r\n        Update(0);\r\n        AfterUpdate(0);\r\n    }\r\n}\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/Shared/IntComponents.cs",
    "content": "﻿namespace Arch.System.SourceGenerator.Tests;\r\n\r\n#pragma warning disable CS0649 // Allow fields to be unassigned for testing purposes\r\ninternal interface IIntComponent\r\n{\r\n    int Value { get; }\r\n}\r\n\r\ninternal struct IntComponentA : IIntComponent\r\n{\r\n    public int Value;\r\n\r\n    readonly int IIntComponent.Value\r\n    {\r\n        get => Value;\r\n    }\r\n}\r\n\r\ninternal struct IntComponentB : IIntComponent\r\n{\r\n    public int Value;\r\n\r\n    readonly int IIntComponent.Value\r\n    {\r\n        get => Value;\r\n    }\r\n}\r\n\r\ninternal struct IntComponentC : IIntComponent\r\n{\r\n    public int Value;\r\n\r\n    readonly int IIntComponent.Value\r\n    {\r\n        get => Value;\r\n    }\r\n}\r\n\r\ninternal struct IntComponentD : IIntComponent\r\n{\r\n    public int Value;\r\n\r\n    readonly int IIntComponent.Value\r\n    {\r\n        get => Value;\r\n    }\r\n}\r\n\r\n#pragma warning restore CS0649\r\n"
  },
  {
    "path": "Arch.System.SourceGenerator.Tests/SystemsTest.cs",
    "content": "﻿using System;\r\nusing Arch.Core;\r\nusing NUnit.Framework;\r\n\r\nnamespace Arch.System.SourceGenerator.Tests;\r\n\r\n/// <summary>\r\n///     Runs tests for systems in each compilation.\r\n///     Note that the compilation is shared across all tests, so the systems are not isolated.\r\n///     As a result, the tests may not be completely independent. However, they are easier to debug.\r\n///     Separately, the same tests are run in isolation in the Arch.System.SourceGenerator.Tests project.\r\n/// </summary>\r\n[TestFixture]\r\ninternal sealed class SystemsTest\r\n{\r\n    /// <summary>\r\n    ///     Tests a system by creating it and running its update method.\r\n    /// </summary>\r\n    /// <typeparam name=\"T\">\r\n    ///     The type of the system to test, which must inherit from BaseSystem and must have a constructor that takes a World parameter.\r\n    /// </typeparam>\r\n    private static void TestSystem<T>() where T : BaseTestSystem\r\n    {\r\n        using var world = World.Create();\r\n        var system = Activator.CreateInstance(typeof(T), world) as T;\r\n        Assert.That(system, Is.Not.Null,\r\n            $\"System instance {typeof(T).Name} should not be null. Ensure it has a constructor that takes a single World param.\");\r\n        system.Setup();\r\n        system.Test();\r\n    }\r\n\r\n    [Test]\r\n    public void BasicCompilation()\r\n    {\r\n        TestSystem<BasicSystem>();\r\n    }\r\n\r\n    [Test]\r\n    public void AttributeQueryCompilation()\r\n    {\r\n        TestSystem<AttributeQuerySystem>();\r\n    }\r\n\r\n    [Test]\r\n    public void ParamQueryCompilation()\r\n    {\r\n        TestSystem<ParamQuerySystem>();\r\n    }\r\n\r\n    [Test]\r\n    public void DataParamCompilation()\r\n    {\r\n        TestSystem<DataParamSystem>();\r\n    }\r\n\r\n    [Test]\r\n    public void GeneratedUpdateCompilation()\r\n    {\r\n        TestSystem<GeneratedUpdateSystem>();\r\n    }\r\n}\r\n"
  },
  {
    "path": "Directory.Build.targets",
    "content": "<Project>\r\n  <Target Name=\"Unity\"\r\n          DependsOnTargets=\"Publish\"\r\n          Condition=\"'$(UnityPublish.Contains(true))'\">\r\n    <PropertyGroup>\r\n      <Configuration>Release</Configuration>\r\n      <UseAppHost>false</UseAppHost>\r\n      <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\r\n    </PropertyGroup>\r\n  </Target>\r\n</Project>\r\n"
  },
  {
    "path": "LICENSE.MD",
    "content": "                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [2022] [genaray / Lars Matthäus]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "README.md",
    "content": "# Arch.Extended\r\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=for-the-badge)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)\r\n[![Nuget](https://img.shields.io/nuget/v/Arch?style=for-the-badge)](https://www.nuget.org/packages/Arch.System/)\r\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)\r\n![C#](https://img.shields.io/badge/c%23-%23239120.svg?style=for-the-badge&logo=c-sharp&logoColor=white)\r\n\r\nExtensions for [Arch](https://github.com/genaray/Arch) with some useful features like Systems, Source Generator and Utils.\r\n \r\n- 🛠️ **_Productive_** >  Adds some useful tools and features to the main repository!\r\n- ☕️ **_SIMPLE_** >  Works easily, reliably and understandably!\r\n- 💪 _**MAINTAINED**_ > It's actively being worked on, maintained, and supported!\r\n- 🚢 _**SUPPORT**_ > Supports .NetStandard 2.1, .Net Core 6 and 7 and therefore you may use it with Unity or Godot!\r\n\r\nDownload the packages and get started today! \r\n```console\r\ndotnet add package Arch.System --version 1.1.0\r\ndotnet add package Arch.System.SourceGenerator --version 2.1.0\r\ndotnet add package Arch.EventBus --version 1.0.2\r\ndotnet add package Arch.LowLevel --version 1.1.5\r\ndotnet add package Arch.Relationships --version 1.0.0\r\ndotnet add package Arch.Persistence --version 2.0.0\r\ndotnet add package Arch.AOT.SourceGenerator --version 1.0.1\r\n```\r\n\r\n# Features & Tools\r\n- ⚙️ **_[Systems](https://github.com/genaray/Arch.Extended/wiki/Systems-API)_** > By means of systems, it is now easy to organize, reuse and arrange queries. \r\n- ✍️ **_[Source Generator](https://github.com/genaray/Arch.Extended/wiki/Source-Generator)_** > Declarative syntax using attributes and source generator, let your queries write themselves! \r\n- ✉️ **_[EventBus](https://github.com/genaray/Arch.Extended/wiki/EventBus)_** > A source generated EventBus, send Events with high-performance!\r\n- 👾 **_[LowLevel](https://github.com/genaray/Arch.Extended/wiki/Lowlevel-&-Resource-Management)_** > Low-level utils and data structures to get rid of GC pressure!\r\n- 💑 **_[Relationships](https://github.com/genaray/Arch.Extended/wiki/Relationships)_** > Adds simple relationships between entities to arch!\r\n- 💾 **_[Persistence](https://github.com/genaray/Arch.Extended/wiki/Persistence)_** > JSON and Binary (de)serialization to persist your Worlds!\r\n- ⌛ **_[AOT Source Generator](https://github.com/genaray/Arch.Extended/wiki/AOT-Source-Generator)_** > Helps with AOT compatibility and reduces boilerplate code! \r\n> Check the links and the [Wiki](https://github.com/genaray/Arch.Extended/wiki)! \r\n\r\n# Full code sample\r\n\r\nWith this package you are able to write and group queries and systems for Arch automatically.\r\nAnd all this with the best possible performance.\r\n\r\nThe tools can be used independently of each other.\r\n\r\n```cs\r\n// Components ( ignore the formatting, this saves space )\r\npublic struct Position{ float X, Y };\r\npublic struct Velocity{ float Dx, Dy };\r\n\r\n// BaseSystem provides several useful methods for interacting and structuring systems\r\npublic class MovementSystem : BaseSystem<World, float>\r\n{\r\n    public MovementSystem(World world) : base(world) {}\r\n    \r\n    // Generates a query and calls that one automatically on BaseSystem.Update\r\n    [Query]\r\n    public void Move([Data] in float time, ref Position pos, ref Velocity vel)\r\n    {\r\n        pos.X += time * vel.X;\r\n        pos.Y += time * vel.Y;\r\n    }\r\n    \r\n    // Generates and filters a query and calls that one automatically on BaseSystem.Update in order\r\n    [Query]\r\n    [All<Player, Mob>, Any<Idle, Moving>, None<Alive>]  // Attributes also accept non generics :) \r\n    public void ResetVelocity(ref Velocity vel)\r\n    {\r\n        vel = new Velocity{ X = 0, Y = 0 };\r\n    }\r\n}\r\n\r\npublic class Game \r\n{\r\n    public static void Main(string[] args) \r\n    {     \r\n        var deltaTime = 0.05f; // This is mostly given by engines, frameworks\r\n        \r\n        // Create a world and a group of systems which will be controlled \r\n        var world = World.Create();\r\n        var _systems = new Group<float>(\r\n            \"Systems\",\r\n            new MovementSystem(world),   // Run in order\r\n            new MyOtherSystem(...),\r\n            ...\r\n        );\r\n      \r\n        _systems.Initialize();                  // Inits all registered systems\r\n        _systems.BeforeUpdate(in deltaTime);    // Calls .BeforeUpdate on all systems ( can be overriden )\r\n        _systems.Update(in deltaTime);          // Calls .Update on all systems ( can be overriden )\r\n        _systems.AfterUpdate(in deltaTime);     // Calls .AfterUpdate on all System ( can be overriden )\r\n        _systems.Dispose();                     // Calls .Dispose on all systems ( can be overriden )\r\n    }\r\n}\r\n```\r\n"
  },
  {
    "path": "scripts/UnityPublish.sh",
    "content": "#!/bin/bash\r\n\r\n# Publishes Unity release to dist/Assemblies using only netstandard2.0 and netstandard2.1\r\n#########################################################################################\r\n\r\ndotnet restore\r\n\r\nassemblyDir=\"`pwd`/dist/Assemblies\"\r\n\r\nrm -rf \"${assemblyDir}\"\r\n\r\nmkdir -p \"${assemblyDir}\"\r\n\r\ndotnet msbuild /t:Unity \\\r\n    -p:PublishDir=\"${assemblyDir}\" \\\r\n    -p:TargetFramework=netstandard2.1 \\\r\n    -p:TargetFrameworks=netstandard2.1 \\\r\n    -p:TargetFrameworkVersion=v2.1\r\n"
  }
]