diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml
index 854fbcd..3e8f8e0 100644
--- a/.github/workflows/build-debug.yml
+++ b/.github/workflows/build-debug.yml
@@ -17,75 +17,6 @@ jobs:
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
with:
dotnet-version: |
- 5.0.x
- 6.0.x
+ 9.0.x
- run: dotnet build -c Debug
- - run: dotnet test -c Debug --no-build
-
- build-unity:
- if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
- strategy:
- fail-fast: false
- max-parallel: 2
- matrix:
- unity: ["2021.3.41f1", "2022.3.39f1", "6000.0.12f1"] # Test with LTS
- runs-on: ubuntu-latest
- timeout-minutes: 15
- steps:
- - name: Load secrets
- id: op-load-secret
- uses: 1password/load-secrets-action@v2
- with:
- export-env: false
- env:
- OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
- UNITY_EMAIL: "op://GitHubActionsPublic/UNITY_LICENSE/username"
- UNITY_PASSWORD: "op://GitHubActionsPublic/UNITY_LICENSE/credential"
- UNITY_SERIAL: "op://GitHubActionsPublic/UNITY_LICENSE/serial"
-
- - uses: actions/checkout@v4
-
- # Execute scripts: Export Package
- # /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- - name: Build Unity (.unitypacakge)
- if: ${{ startsWith(matrix.unity, '2021') }} # only execute once
- uses: Cysharp/Actions/.github/actions/unity-builder@main
- env:
- UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
- UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
- UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
- with:
- projectPath: src/MasterMemory.Unity
- unityVersion: ${{ matrix.unity }}
- targetPlatform: StandaloneLinux64
- buildMethod: PackageExporter.Export
-
- - uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
- with:
- directory: src/MasterMemory.Unity
-
- # Execute Unittest
- # /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend IL2CPP /BuildTarget StandaloneLinux64
- - name: Build UnitTest (IL2CPP)
- uses: Cysharp/Actions/.github/actions/unity-builder@main
- env:
- UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
- UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
- UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
- with:
- projectPath: src/MasterMemory.Unity
- unityVersion: ${{ matrix.unity }}
- targetPlatform: StandaloneLinux64
- buildMethod: UnitTestBuilder.BuildUnitTest
- customParameters: "/headless /ScriptBackend IL2CPP"
- - name: Check UnitTest file is generated
- run: ls -lR ./src/MasterMemory.Unity/bin/UnitTest
- - name: Execute UnitTest
- run: ./src/MasterMemory.Unity/bin/UnitTest/StandaloneLinux64_IL2CPP/test
-
- # Store artifacts.
- - uses: Cysharp/Actions/.github/actions/upload-artifact@main
- with:
- name: MasterMemory.${{ matrix.unity }}.unitypackage.zip
- path: ./src/MasterMemory.Unity/*.unitypackage
- retention-days: 1
+ - run: dotnet test -c Debug --no-build
\ No newline at end of file
diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml
index cac196a..6ee5340 100644
--- a/.github/workflows/build-release.yml
+++ b/.github/workflows/build-release.yml
@@ -13,30 +13,15 @@ on:
type: boolean
jobs:
- update-packagejson:
- uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
- with:
- file-path: ./src/MasterMemory.Unity/Assets/Scripts/MasterMemory/package.json
- tag: ${{ inputs.tag }}
- dry-run: ${{ inputs.dry-run }}
- push-tag: false
-
build-dotnet:
- needs: [update-packagejson]
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- with:
- ref: ${{ needs.update-packagejson.outputs.sha }}
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- with:
- dotnet-version: |
- 5.0.x
- 6.0.x
# pack nuget
- run: dotnet build -c Release -p:Version=${{ inputs.tag }}
- - run: dotnet test -c Release --no-build -p:Version=${{ inputs.tag }}
+ - run: dotnet test -c Release --no-build
- run: dotnet pack -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
with:
@@ -44,72 +29,13 @@ jobs:
path: ./publish
retention-days: 1
- build-unity:
- needs: [update-packagejson]
- strategy:
- matrix:
- unity: ["2022.3.39f1"]
- runs-on: ubuntu-latest
- timeout-minutes: 15
- steps:
- - name: Load secrets
- id: op-load-secret
- uses: 1password/load-secrets-action@v2
- with:
- export-env: false
- env:
- OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
- UNITY_EMAIL: "op://GitHubActionsPublic/UNITY_LICENSE/username"
- UNITY_PASSWORD: "op://GitHubActionsPublic/UNITY_LICENSE/credential"
- UNITY_SERIAL: "op://GitHubActionsPublic/UNITY_LICENSE/serial"
-
- - run: echo ${{ needs.update-packagejson.outputs.sha }}
- - uses: actions/checkout@v4
- with:
- ref: ${{ needs.update-packagejson.outputs.sha }}
-
- # Execute scripts: Export Package
- # /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- - name: Build Unity (.unitypacakge)
- uses: Cysharp/Actions/.github/actions/unity-builder@main
- env:
- UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
- UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
- UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
- UNITY_PACKAGE_VERSION: ${{ inputs.tag }}
- with:
- projectPath: src/MasterMemory.Unity
- unityVersion: ${{ matrix.unity }}
- targetPlatform: StandaloneLinux64
- buildMethod: PackageExporter.Export
-
- - uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
- with:
- directory: src/MasterMemory.Unity
-
- # Store artifacts.
- - uses: Cysharp/Actions/.github/actions/upload-artifact@main
- with:
- name: MasterMemory.Unity.${{ inputs.tag }}.unitypackage
- path: ./src/MasterMemory.Unity/MasterMemory.Unity.${{ inputs.tag }}.unitypackage
- retention-days: 1
-
# release
create-release:
- needs: [update-packagejson, build-dotnet, build-unity]
+ needs: [build-dotnet]
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
with:
- commit-id: ${{ needs.update-packagejson.outputs.sha }}
+ commit-id: ${{ github.sha }}
dry-run: ${{ inputs.dry-run }}
tag: ${{ inputs.tag }}
nuget-push: true
- release-upload: true
- release-asset-path: ./MasterMemory.Unity.${{ inputs.tag }}.unitypackage/MasterMemory.Unity.${{ inputs.tag }}.unitypackage
- secrets: inherit
-
- cleanup:
- if: ${{ needs.update-packagejson.outputs.is-branch-created == 'true' }}
- needs: [update-packagejson, build-unity]
- uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
- with:
- branch: ${{ needs.update-packagejson.outputs.branch-name }}
+ secrets: inherit
\ No newline at end of file
diff --git a/MasterMemory.sln b/MasterMemory.sln
index 510f348..f7489c6 100644
--- a/MasterMemory.sln
+++ b/MasterMemory.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28729.10
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{60662102-4523-441E-8D6C-D87A3246C648}"
EndProject
@@ -15,17 +15,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.Tests", "tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.Annotations", "src\MasterMemory.Annotations\MasterMemory.Annotations.csproj", "{A13F40DD-7777-4E97-9FC4-6324722CA964}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.GeneratorCore", "src\MasterMemory.GeneratorCore\MasterMemory.GeneratorCore.csproj", "{DAC2FED6-E960-4E57-949F-6B9185924E60}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.Generator", "src\MasterMemory.Generator\MasterMemory.Generator.csproj", "{625ECD09-F1E4-4979-B7A6-F94F23F7BBB0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "sandbox\Benchmark\Benchmark.csproj", "{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "sandbox\ConsoleApp\ConsoleApp.csproj", "{2657C9C5-0BEA-4616-BE41-A19E8298C591}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfTest2", "sandbox\PerfTest2\PerfTest2.csproj", "{AA5B5485-C42E-449C-843A-98A99A0D10B2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterMemory.MSBuild.Tasks", "src\MasterMemory.MSBuild.Tasks\MasterMemory.MSBuild.Tasks.csproj", "{433D4291-D2E3-4F36-8F2E-3E47F620DC9F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterMemory.SourceGenerator", "src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj", "{73F0ABAF-E55F-4E63-923B-4ABDE794D490}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeneratorSandbox", "sandbox\GeneratorSandbox\GeneratorSandbox.csproj", "{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterMemory.SourceGenerator.Tests", "tests\MasterMemory.SourceGenerator.Tests\MasterMemory.SourceGenerator.Tests.csproj", "{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -45,14 +45,6 @@ Global
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Release|Any CPU.Build.0 = Release|Any CPU
- {DAC2FED6-E960-4E57-949F-6B9185924E60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DAC2FED6-E960-4E57-949F-6B9185924E60}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DAC2FED6-E960-4E57-949F-6B9185924E60}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DAC2FED6-E960-4E57-949F-6B9185924E60}.Release|Any CPU.Build.0 = Release|Any CPU
- {625ECD09-F1E4-4979-B7A6-F94F23F7BBB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {625ECD09-F1E4-4979-B7A6-F94F23F7BBB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {625ECD09-F1E4-4979-B7A6-F94F23F7BBB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {625ECD09-F1E4-4979-B7A6-F94F23F7BBB0}.Release|Any CPU.Build.0 = Release|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -65,10 +57,18 @@ Global
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Release|Any CPU.Build.0 = Release|Any CPU
- {433D4291-D2E3-4F36-8F2E-3E47F620DC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {433D4291-D2E3-4F36-8F2E-3E47F620DC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {433D4291-D2E3-4F36-8F2E-3E47F620DC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {433D4291-D2E3-4F36-8F2E-3E47F620DC9F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -77,12 +77,12 @@ Global
{D2720BBB-C233-4A1E-9768-1F00C9602180} = {60662102-4523-441E-8D6C-D87A3246C648}
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F} = {BDAFF1CB-8E53-412B-B389-42A15343C7A3}
{A13F40DD-7777-4E97-9FC4-6324722CA964} = {60662102-4523-441E-8D6C-D87A3246C648}
- {DAC2FED6-E960-4E57-949F-6B9185924E60} = {60662102-4523-441E-8D6C-D87A3246C648}
- {625ECD09-F1E4-4979-B7A6-F94F23F7BBB0} = {60662102-4523-441E-8D6C-D87A3246C648}
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{2657C9C5-0BEA-4616-BE41-A19E8298C591} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{AA5B5485-C42E-449C-843A-98A99A0D10B2} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
- {433D4291-D2E3-4F36-8F2E-3E47F620DC9F} = {60662102-4523-441E-8D6C-D87A3246C648}
+ {73F0ABAF-E55F-4E63-923B-4ABDE794D490} = {60662102-4523-441E-8D6C-D87A3246C648}
+ {D1D2B635-99CC-4C90-BAAB-57D188B5BE42} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
+ {96F54302-35CD-4CDC-AAAC-8A6858DCAFEB} = {BDAFF1CB-8E53-412B-B389-42A15343C7A3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0121A3C4-6AE0-4622-BE04-05D9A3E729AC}
diff --git a/README.md b/README.md
index b6674b3..ecc3a46 100644
--- a/README.md
+++ b/README.md
@@ -2,30 +2,37 @@
MasterMemory
===
-
-Embedded Typed Readonly In-Memory Document Database for .NET Core and Unity.
+Source Generator based Embedded Typed Readonly In-Memory Document Database for .NET and Unity.
![image](https://user-images.githubusercontent.com/46207/61031896-61890800-a3fb-11e9-86b7-84c821d347a4.png)
**4700** times faster than SQLite and achieves zero allocation per query. Also the DB size is small. When SQLite is 3560kb then MasterMemory is only 222kb.
+Source Generator automatically generates a typed database structure from schemas (classes), which ensures that all queries are type-safe with full autocompletion support.
+
+![image](https://github.com/user-attachments/assets/e804fa52-f6a5-4972-a510-0b3b17a31230)
+
+![image](https://user-images.githubusercontent.com/46207/61035808-cb58e000-a402-11e9-9209-d51665d1cd56.png)
+
+This ensures both optimal performance and excellent usability.
+
## Table of Contents
- [Concept](#concept)
-- [Getting Started(.NET Core)](#getting-startednet-core)
+- [Getting Started(.NET)](#getting-startednet)
- [Getting Started(Unity)](#getting-startedunity)
- [DataTable configuration](#datatable-configuration)
- [MemoryDatabase/RangeView](#memorydatabaserangeview)
- [Extend Table](#extend-table)
- [ImmutableBuilder](#immutablebuilder)
-- [Immutable Data](#immutable-data)
- [Validator](#validator)
- [Metadata](#metadata)
- [Inheritance](#inheritance)
- [Optimization](#optimization)
-- [Code Generator](#code-generator)
+- [MasterMemoryGeneratorOptions](#mastermemorygeneratoroptions)
+- [v2 -> v3 migration](#v2---v3-migration)
- [License](#license)
@@ -35,21 +42,19 @@ Concept
* **Memory Efficient**, Only use underlying data memory and do aggressively string interning.
* **Performance**, Similar as dictionary lookup.
-* **TypeSafe**, 100% Type safe by pre code-generation.
+* **TypeSafe**, 100% Type safe by Source Generator.
* **Fast load speed**, MasterMemory save data by [MessagePack for C#, a fastest C# serializer](https://github.com/neuecc/MessagePack-CSharp) so load speed is blazing fast.
* **Flexible Search**, Supports multiple key, multiple result, range/closest query.
* **Validator**, You can define custom data validation by C#.
* **Metadata**, To make custom importer/exporter, get the all database metadata.
-These features are suitable for master data management(write-once, read-heavy) on embedded application such as role-playing game. MasterMemory has better performance than any other database solutions. [PalDB](https://github.com/linkedin/PalDB) developed by LinkedIn has a similar concept(embeddable write-once key-value store), but the implementation and performance characteristics are completely different.
+These features are suitable for master data management(write-once, read-heavy) on embedded application, data analysis, game, etc. MasterMemory has better performance than any other database solutions. [PalDB](https://github.com/linkedin/PalDB) developed by LinkedIn has a similar concept(embeddable write-once key-value store), but the implementation and performance characteristics are completely different.
-Getting Started(.NET Core)
+Getting Started(.NET)
---
-MasterMemory uses C# to C# code-generator. Runtime library API is the same but how to code-generate has different way between .NET Core and Unity. This sample is for .NET Core(for Unity is in below sections).
-
-Install the core library(Runtime and [Annotations](https://www.nuget.org/packages/MasterMemory.Annotations)).
+Install the library(Runtime, Source Generator(Analyzer) and [Annotations](https://www.nuget.org/packages/MasterMemory.Annotations)) via NuGet.
-> PM> Install-Package [MasterMemory](https://www.nuget.org/packages/MasterMemory)
+> dotnet add package [MasterMemory](https://www.nuget.org/packages/MasterMemory)
Prepare the example table definition like following.
@@ -62,62 +67,50 @@ public enum Gender
// table definition marked by MemoryTableAttribute.
// database-table must be serializable by MessagePack-CSsharp
[MemoryTable("person"), MessagePackObject(true)]
-public class Person
+public record Person
{
// index definition by attributes.
[PrimaryKey]
- public int PersonId { get; set; }
+ public required int PersonId { get; init; }
// secondary index can add multiple(discriminated by index-number).
[SecondaryKey(0), NonUnique]
[SecondaryKey(1, keyOrder: 1), NonUnique]
- public int Age { get; set; }
+ public required int Age { get; init; }
[SecondaryKey(2), NonUnique]
[SecondaryKey(1, keyOrder: 0), NonUnique]
- public Gender Gender { get; set; }
+ public required Gender Gender { get; init; }
- public string Name { get; set; }
+ public required string Name { get; init; }
}
```
-Edit the `.csproj`, add [MasterMemory.MSBuild.Tasks](https://www.nuget.org/packages/MasterMemory.MSBuild.Tasks) and add configuration like following.
-
-```xml
-
-
-
-
-
-
-
-
-
-
-
-```
+Data in MasterMemory is readonly, so it is recommended to use an immutable structure. While both records and classes are supported, records might be preferable as they generate more readable ToString methods.
-After the build, generated files(`DatabaseBuilder.cs`, `ImmutableBuilder.cs`, `MasterMemoryResolver.cs`, `MemoryDatabase.cs` and `Tables/***Table.cs`) in OutputDirectory.
+MasterMemory's Source Generator detects types marked with the `MemoryTable` attribute and automatically generates types like the following:
-![image](https://user-images.githubusercontent.com/46207/61233535-ba460100-a76b-11e9-85d0-c34cb5ce7482.png)
+![image](https://github.com/user-attachments/assets/e804fa52-f6a5-4972-a510-0b3b17a31230)
Finally, you can regsiter and query by these files.
```csharp
+using ...; // Your project default namespace
+
// to create database, use DatabaseBuilder and Append method.
var builder = new DatabaseBuilder();
builder.Append(new Person[]
{
- new Person { PersonId = 0, Age = 13, Gender = Gender.Male, Name = "Dana Terry" },
- new Person { PersonId = 1, Age = 17, Gender = Gender.Male, Name = "Kirk Obrien" },
- new Person { PersonId = 2, Age = 31, Gender = Gender.Male, Name = "Wm Banks" },
- new Person { PersonId = 3, Age = 44, Gender = Gender.Male, Name = "Karl Benson" },
- new Person { PersonId = 4, Age = 23, Gender = Gender.Male, Name = "Jared Holland" },
- new Person { PersonId = 5, Age = 27, Gender = Gender.Female, Name = "Jeanne Phelps" },
- new Person { PersonId = 6, Age = 25, Gender = Gender.Female, Name = "Willie Rose" },
- new Person { PersonId = 7, Age = 11, Gender = Gender.Female, Name = "Shari Gutierrez" },
- new Person { PersonId = 8, Age = 63, Gender = Gender.Female, Name = "Lori Wilson" },
- new Person { PersonId = 9, Age = 34, Gender = Gender.Female, Name = "Lena Ramsey" },
+ new (){ PersonId = 0, Age = 13, Gender = Gender.Male, Name = "Dana Terry" },
+ new (){ PersonId = 1, Age = 17, Gender = Gender.Male, Name = "Kirk Obrien" },
+ new (){ PersonId = 2, Age = 31, Gender = Gender.Male, Name = "Wm Banks" },
+ new (){ PersonId = 3, Age = 44, Gender = Gender.Male, Name = "Karl Benson" },
+ new (){ PersonId = 4, Age = 23, Gender = Gender.Male, Name = "Jared Holland" },
+ new (){ PersonId = 5, Age = 27, Gender = Gender.Female, Name = "Jeanne Phelps" },
+ new (){ PersonId = 6, Age = 25, Gender = Gender.Female, Name = "Willie Rose" },
+ new (){ PersonId = 7, Age = 11, Gender = Gender.Female, Name = "Shari Gutierrez" },
+ new (){ PersonId = 8, Age = 63, Gender = Gender.Female, Name = "Lori Wilson" },
+ new (){ PersonId = 9, Age = 34, Gender = Gender.Female, Name = "Lena Ramsey" },
});
// build database binary(you can also use `WriteToStream` for save to file).
@@ -130,7 +123,7 @@ byte[] data = builder.Build();
var db = new MemoryDatabase(data);
// .PersonTable.FindByPersonId is fully typed by code-generation.
-Person person = db.PersonTable.FindByPersonId(10);
+Person person = db.PersonTable.FindByPersonId(5);
// Multiple key is also typed(***And * **), Return value is multiple if key is marked with `NonUnique`.
RangeView result = db.PersonTable.FindByGenderAndAge((Gender.Female, 23));
@@ -150,9 +143,26 @@ You can invoke all indexed query by IntelliSense.
Getting Started(Unity)
---
-Check the [releases](https://github.com/Cysharp/MasterMemory/releases) page, download `MasterMemory.Unity.unitypackage`(runtime) and `MasterMemory.Generator.zip`(cli code-generator). MasterMemory also depends on MessagePack-CSharp so you have to download `MessagePack.Unity.2.*.*.unitypackage` and `mpc.zip` from [MessagePack-CSharp/releases page](https://github.com/neuecc/MessagePack-CSharp/releases).
+The minimum supported Unity version will be `2022.3.12f1`, as it is necessary to support C# Incremental Source Generator(Compiler Version, 4.3.0).
-Prepare the example table definition like following.
+Since this library is provided via NuGet, install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity), then navigate to Open Window from NuGet -> Manage NuGet Packages, Search "MasterMemory" and Press Install.
+
+First, it is recommended to define assembly attributes in any cs file to enable the use of `init`.
+
+```csharp
+// Optional: Unity can't load default namespace to Source Generator
+// If not specified, 'MasterMemory' will be used by default,
+// but you can use this attribute if you want to specify a different namespace.
+[assembly: MasterMemoryGeneratorOptions(Namespace = "MyProj")]
+
+// Optional: If you want to use init keyword, copy-and-paste this.
+namespace System.Runtime.CompilerServices
+{
+ internal sealed class IsExternalInit { }
+}
+```
+
+Everything else is the same as the standard .NET version. While the `required` keyword can't be used since it's from C# 11, using `init` alone is sufficient to guarantee immutability.
```csharp
public enum Gender
@@ -163,46 +173,26 @@ public enum Gender
// table definition marked by MemoryTableAttribute.
// database-table must be serializable by MessagePack-CSsharp
[MemoryTable("person"), MessagePackObject(true)]
-public class Person
+public record Person
{
// index definition by attributes.
[PrimaryKey]
- public int PersonId { get; set; }
+ public int PersonId { get; init; }
// secondary index can add multiple(discriminated by index-number).
[SecondaryKey(0), NonUnique]
[SecondaryKey(1, keyOrder: 1), NonUnique]
- public int Age { get; set; }
+ public int Age { get; init; }
[SecondaryKey(2), NonUnique]
[SecondaryKey(1, keyOrder: 0), NonUnique]
- public Gender Gender { get; set; }
+ public Gender Gender { get; init; }
- public string Name { get; set; }
+ public string Name { get; init; }
}
```
-use the MasterMemory code generator by commandline. Commandline tool support platforms are `win-x64`, `osx-x64` and `linux-x64`.
-
-```
-Usage: MasterMemory.Generator [options...]
-
-Options:
- -i, -inputDirectory Input file directory(search recursive). (Required)
- -o, -outputDirectory Output file directory. (Required)
- -n, -usingNamespace Namespace of generated files. (Required)
- -p, -prefixClassName Prefix of class names. (Default: )
- -c, -addImmutableConstructor Add immutable constructor to MemoryTable class. (Default: False)
- -t, -returnNullIfKeyNotFound Return null if key not found on unique find method. (Default: False)
-```
-
-```bash
-MasterMemory.Generator.exe -i "C:\UnitySample" -o "C:\UnitySample\Generated" -n "UnitySample"
-```
-
-Also you need to generated MessagePack-CSharp code generation.
-
-Additional steps, you have to set up to use generated resolver.
+Also, for use with IL2CPP, you need to add the generated `MasterMemoryResolver` to MessagePack's Resolver. If you need other generated Resolvers, such as those from [MagicOnion](https://github.com/Cysharp/MagicOnion), please add and compose them here.
```csharp
public static class Initializer
@@ -210,65 +200,21 @@ public static class Initializer
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void SetupMessagePackResolver()
{
+ // Create CompositeResolver
StaticCompositeResolver.Instance.Register(new[]{
MasterMemoryResolver.Instance, // set MasterMemory generated resolver
- GeneratedResolver.Instance, // set MessagePack generated resolver
StandardResolver.Instance // set default MessagePack resolver
});
+ // Create options with resolver
var options = MessagePackSerializerOptions.Standard.WithResolver(StaticCompositeResolver.Instance);
+
+ // Optional: as default.
MessagePackSerializer.DefaultOptions = options;
}
}
```
-The rest is the same as .NET Core version.
-
-```csharp
-// to create database, use DatabaseBuilder and Append method.
-var builder = new DatabaseBuilder();
-builder.Append(new Person[]
-{
- new Person { PersonId = 0, Age = 13, Gender = Gender.Male, Name = "Dana Terry" },
- new Person { PersonId = 1, Age = 17, Gender = Gender.Male, Name = "Kirk Obrien" },
- new Person { PersonId = 2, Age = 31, Gender = Gender.Male, Name = "Wm Banks" },
- new Person { PersonId = 3, Age = 44, Gender = Gender.Male, Name = "Karl Benson" },
- new Person { PersonId = 4, Age = 23, Gender = Gender.Male, Name = "Jared Holland" },
- new Person { PersonId = 5, Age = 27, Gender = Gender.Female, Name = "Jeanne Phelps" },
- new Person { PersonId = 6, Age = 25, Gender = Gender.Female, Name = "Willie Rose" },
- new Person { PersonId = 7, Age = 11, Gender = Gender.Female, Name = "Shari Gutierrez" },
- new Person { PersonId = 8, Age = 63, Gender = Gender.Female, Name = "Lori Wilson" },
- new Person { PersonId = 9, Age = 34, Gender = Gender.Female, Name = "Lena Ramsey" },
-});
-
-// build database binary(you can also use `WriteToStream` for save to file).
-byte[] data = builder.Build();
-
-// -----------------------
-
-// for query phase, create MemoryDatabase.
-// (MemoryDatabase is recommended to store in singleton container(static field/DI)).
-var db = new MemoryDatabase(data);
-
-// .PersonTable.FindByPersonId is fully typed by code-generation.
-Person person = db.PersonTable.FindByPersonId(10);
-
-// Multiple key is also typed(***And * **), Return value is multiple if key is marked with `NonUnique`.
-RangeView result = db.PersonTable.FindByGenderAndAge((Gender.Female, 23));
-
-// Get nearest value(choose lower(default) or higher).
-RangeView age1 = db.PersonTable.FindClosestByAge(31);
-
-// Get range(min-max inclusive).
-RangeView age2 = db.PersonTable.FindRangeByAge(20, 29);
-```
-
-All table(marked by `MemoryTableAttribute`) and methods(created by `PrimaryKeyAttribute` or `SecondaryKeyAttribute`) are typed.
-
-![image](https://user-images.githubusercontent.com/46207/61035808-cb58e000-a402-11e9-9209-d51665d1cd56.png)
-
-You can invoke all indexed query by IntelliSense.
-
DataTable configuration
---
Element type of datatable must be marked by `[MemoryTable(tableName)]`, datatable is generated from marked type. `string tableName` is saved in database binary, you can rename class name if tableName is same.
@@ -473,48 +419,6 @@ public class GameRoom
}
```
-Immutable Data
----
-Element data is shared in the application so ideally should be immutable. But C# only has a constructor to create immutable data, it is too difficult to create many data tables.
-
-Code generator has `AddImmutableConstructor`(`-c, -addImmutableConstructor`) option. If enabled it, code generator modify orignal file and add immutable constructor in target type. If you define property as `{get; private set;}` or `{get;}`, it will be immutable type.
-
-```csharp
-// For the versioning, MessagePackObject is recommended to use string key.
-[MemoryTable("person"), MessagePackObject(true)]
-public class Person
-{
- [PrimaryKey]
- public int PersonId { get; }
- public int Age { get; }
- public Gender Gender { get; }
- public string Name { get; }
-}
-
-// use AddImmutableConstructor="true" or -c option
-
-MasterMemory.Generator.exe -i "C:\UnitySample" -o "C:\UnitySample\Generated" -n "UnitySample" -c
-
-// after generated...
-[MemoryTable("person"), MessagePackObject(true)]
-public class Person
-{
- [PrimaryKey]
- public int PersonId { get; }
- public int Age { get; }
- public Gender Gender { get; }
- public string Name { get; }
-
- public Person(int PersonId, int Age, Gender Gender, string Name)
- {
- this.PersonId = PersonId;
- this.Age = Age;
- this.Gender = Gender;
- this.Name = Name;
- }
-}
-```
-
Validator
---
You can validate data by `MemoryDatabase.Validate` method. In default, it check unique key(data duplicated) and you can define custom validate logics.
@@ -642,58 +546,54 @@ If creates console-app, our [ConsoleAppFramework](https://github.com/Cysharp/Con
Here is sample of reading and creating dynamic from csv. `builder.AppendDynamic` and `System.Runtime.Serialization.FormatterServices.GetUninitializedObject` will help it.
```csharp
-class Program
-{
- static void Main(string[] args)
- {
- var csv = @"monster_id,name,max_hp
+var csv = @"monster_id,name,max_hp
1,foo,100
2,bar,200";
- var fileName = "monster";
+var fileName = "monster";
- var builder = new DatabaseBuilder();
+var builder = new DatabaseBuilder();
+
+var meta = MemoryDatabase.GetMetaDatabase();
+var table = meta.GetTableInfo(fileName);
- var meta = MemoryDatabase.GetMetaDatabase();
- var table = meta.GetTableInfo(fileName);
+var tableData = new List