Skip to content

Commit

Permalink
Merge pull request #85 from Nexus-Mods/tuple3
Browse files Browse the repository at this point in the history
Tuple3
  • Loading branch information
halgari authored Aug 5, 2024
2 parents 58605d7 + 3cd25b2 commit 2731cc4
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 25 deletions.
79 changes: 79 additions & 0 deletions src/NexusMods.MnemonicDB.Abstractions/Attributes/TupleAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,82 @@ protected override (T1LowLevel, T2LowLevel) ToLowLevel((T1HighLevel, T2HighLevel
throw new NotSupportedException("This attribute uses custom serialization, and does not support low-level conversion.");
}
}


public class TupleAttribute<T1HighLevel, T1LowLevel, T2HighLevel, T2LowLevel, T3HighLevel, T3LowLevel> :
ScalarAttribute<(T1HighLevel, T2HighLevel, T3HighLevel), (T1LowLevel, T2LowLevel, T3LowLevel)>
{
private readonly ValueTags _tag1;
private readonly ValueTags _tag2;
private readonly ValueTags _tag3;

/// <summary>
/// Creates a new tuple attribute, the value tags are used to determine the type of each elelement in the tuple.
/// </summary>
public TupleAttribute(ValueTags tag1, ValueTags tag2, ValueTags tag3, string ns, string name) : base(ValueTags.Tuple3, ns, name)
{
_tag1 = tag1;
_tag2 = tag2;
_tag3 = tag3;
}

/// <inheritdoc />
public override (T1HighLevel, T2HighLevel, T3HighLevel) ReadValue(ReadOnlySpan<byte> span, ValueTags tag, RegistryId registryId)
{
if (tag != ValueTags.Tuple3)
throw new ArgumentException($"Expected tag {ValueTags.Tuple3}, but got {tag}");

var type1 = span[0];
var type2 = span[1];
var type3 = span[2];

if (type1 != (byte)_tag1 || type2 != (byte)_tag2 || type3 != (byte)_tag3)
throw new ArgumentException($"Expected tag ({_tag1}, {_tag2}, {_tag3}), but got ({type1}, {type2}, {type3})");

var valA = ReadValue<T1LowLevel>(span.SliceFast(3), _tag1, registryId, out var sizeA);
var valB = ReadValue<T2LowLevel>(span.SliceFast(3 + sizeA), _tag2, registryId, out var sizeB);
var valC = ReadValue<T3LowLevel>(span.SliceFast(3 + sizeA + sizeB), _tag3, registryId, out _);

return FromLowLevel((valA, valB, valC));
}

/// <inheritdoc />
protected virtual (T1HighLevel, T2HighLevel, T3HighLevel) FromLowLevel((T1LowLevel, T2LowLevel, T3LowLevel) value)
{
throw new NotSupportedException("You must override this method to support low-level conversion.");
}

public override void Remap(Func<EntityId, EntityId> remapper, Span<byte> valueSpan)
{
if (_tag1 == ValueTags.Reference)
{
var entityId = MemoryMarshal.Read<EntityId>(valueSpan.SliceFast(2));
var newEntityId = remapper(entityId);
MemoryMarshal.Write(valueSpan.SliceFast(2), newEntityId);
}
else if (_tag2 == ValueTags.Reference)
{
throw new NotImplementedException();
}
}

/// <inheritdoc />
public override void WriteValue<TWriter>((T1HighLevel, T2HighLevel, T3HighLevel) value, TWriter writer)
{
var span = writer.GetSpan(3);
span[0] = (byte)_tag1;
span[1] = (byte)_tag2;
span[2] = (byte)_tag3;
writer.Advance(3);

WriteValueLowLevel(value.Item1, _tag1, writer);
WriteValueLowLevel(value.Item2, _tag2, writer);
WriteValueLowLevel(value.Item3, _tag3, writer);
}

/// <inheritdoc />
protected override (T1LowLevel, T2LowLevel, T3LowLevel) ToLowLevel((T1HighLevel, T2HighLevel, T3HighLevel) value)
{
throw new NotSupportedException("This attribute uses custom serialization, and does not support low-level conversion.");
}
}
18 changes: 18 additions & 0 deletions tests/NexusMods.MnemonicDB.TestModel/Attributes/Int3Attribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;

namespace NexusMods.MnemonicDB.TestModel.Attributes;

public class Int3Attribute(string ns, string name) : TupleAttribute<int, int, int, int, int, int>(ValueTags.Int32, ValueTags.Int32, ValueTags.Int32, ns, name)
{
protected override (int, int, int) FromLowLevel((int, int, int) value)
{
return value;
}

protected override (int, int, int) ToLowLevel((int, int, int) value)
{
return value;
}
}
6 changes: 6 additions & 0 deletions tests/NexusMods.MnemonicDB.TestModel/File.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;
using NexusMods.MnemonicDB.Abstractions.Models;
using NexusMods.MnemonicDB.TestModel.Attributes;

Expand All @@ -17,4 +18,9 @@ public partial class File : IModelDefinition
/// A combination of the loadout
/// </summary>
public static readonly TuplePath TuplePath = new(Namespace, nameof(TuplePath)) {IsIndexed = true, IsOptional = true};

/// <summary>
/// Tuple3 test
/// </summary>
public static readonly Int3Attribute TupleTest = new(Namespace, nameof(TupleTest)) { IsIndexed = true, IsOptional = true};
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
+ | 0200000000000002 | (0010) Name | Mod1 - Updated | 0100000000000004
+ | 0200000000000002 | (0011) Source | http://somesite.com/Mod1 | 0100000000000003
+ | 0200000000000002 | (0012) Loadout | 0200000000000001 | 0100000000000003
+ | 0200000000000002 | (0011) Name | Mod1 - Updated | 0100000000000004
+ | 0200000000000002 | (0012) Source | http://somesite.com/Mod1 | 0100000000000003
+ | 0200000000000002 | (0013) Loadout | 0200000000000001 | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
+ | 0100000000000003 | (0008) Timestamp | DateTime : 0 | 0100000000000003
+ | 0200000000000001 | (001D) Name | Parent A | 0100000000000003
+ | 0200000000000001 | (001E) Name | Parent B | 0100000000000003
+ | 0200000000000001 | (001F) Name | Test Child | 0100000000000003
+ | 0200000000000001 | (001E) Name | Parent A | 0100000000000003
+ | 0200000000000001 | (001F) Name | Parent B | 0100000000000003
+ | 0200000000000001 | (0020) Name | Test Child | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
+ | 0100000000000003 | (0008) Timestamp | DateTime : 0 | 0100000000000003
+ | 0200000000000001 | (001D) Name | Parent A | 0100000000000003
+ | 0200000000000001 | (001E) Name | Parent B | 0100000000000003
+ | 0200000000000001 | (001F) Name | Test Child | 0100000000000003
+ | 0200000000000001 | (001E) Name | Parent A | 0100000000000003
+ | 0200000000000001 | (001F) Name | Parent B | 0100000000000003
+ | 0200000000000001 | (0020) Name | Test Child | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
+ | 0200000000000001 | (0010) Name | Test Mod | 0100000000000003
+ | 0200000000000001 | (0011) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0012) Loadout | 0200000000000002 | 0100000000000003
+ | 0200000000000001 | (0011) Name | Test Mod | 0100000000000003
+ | 0200000000000001 | (0012) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0013) Loadout | 0200000000000002 | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
+ | 0200000000000001 | (0010) Name | Test Mod 0 | 0100000000000004
+ | 0200000000000001 | (0011) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0012) Loadout | 0200000000000002 | 0100000000000003
+ | 0200000000000001 | (0011) Name | Test Mod 0 | 0100000000000004
+ | 0200000000000001 | (0012) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0013) Loadout | 0200000000000002 | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
+ | 0200000000000001 | (0010) Name | Test Mod 1 | 0100000000000005
+ | 0200000000000001 | (0011) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0012) Loadout | 0200000000000002 | 0100000000000003
+ | 0200000000000001 | (0011) Name | Test Mod 1 | 0100000000000005
+ | 0200000000000001 | (0012) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0013) Loadout | 0200000000000002 | 0100000000000003
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
+ | 0200000000000001 | (0010) Name | Test Mod 2 | 0100000000000006
+ | 0200000000000001 | (0011) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0012) Loadout | 0200000000000002 | 0100000000000003
+ | 0200000000000001 | (0011) Name | Test Mod 2 | 0100000000000006
+ | 0200000000000001 | (0012) Source | http://test.com/ | 0100000000000003
+ | 0200000000000001 | (0013) Loadout | 0200000000000002 | 0100000000000003
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
+ | 0200000000000001 | (000A) Hash | 0x00000000DEADBEF0 | 0100000000000003
+ | 0200000000000001 | (000B) Size | 1 B | 0100000000000003
+ | 0200000000000001 | (000C) Mod | 0000000000000001 | 0100000000000003
+ | 0200000000000001 | (000E) Path | C:\test.zip | 0100000000000003
+ | 0200000000000001 | (000F) Hash | 0x00000000FEEDBEEF | 0100000000000003
+ | 0200000000000001 | (000F) Path | C:\test.zip | 0100000000000003
+ | 0200000000000001 | (0010) Hash | 0x00000000FEEDBEEF | 0100000000000003
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
+ | 0200000000000001 | (000A) Hash | 0x00000000DEADBEF0 | 0100000000000003
+ | 0200000000000001 | (000B) Size | 1 B | 0100000000000003
+ | 0200000000000001 | (000C) Mod | 0000000000000001 | 0100000000000003
+ | 0200000000000001 | (000E) Path | C:\test.zip | 0100000000000003
+ | 0200000000000001 | (000F) Hash | 0x00000000FEEDBEEF | 0100000000000003
+ | 0200000000000001 | (000F) Path | C:\test.zip | 0100000000000003
+ | 0200000000000001 | (0010) Hash | 0x00000000FEEDBEEF | 0100000000000003
20 changes: 20 additions & 0 deletions tests/NexusMods.MnemonicDB.Tests/DbTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,26 @@ public async Task CanWriteTupleAttributes()
var avet = Connection.Db.Datoms(SliceDescriptor.Create(File.TuplePath, (EntityId.From(0), ""), (EntityId.MaxValueNoPartition, ""), Connection.Db.Registry));
await VerifyTable(avet.Resolved());
}

[Fact]
public async Task CanUseTuple3Attributes()
{
using var tx = Connection.BeginTransaction();
var fileA = new File.New(tx)
{
Path = "C:\\test.txt",
Hash = Hash.From(0xDEADBEEF),
Size = Size.From(1),
ModId = EntityId.From(0),
TupleTest = (1, 2, 3)
};

var results = await tx.Commit();

var file = results.Remap(fileA);

file.TupleTest.Should().Be((1, 2, 3));
}

[Fact]
public async Task CanGetAnalyzerData()
Expand Down

0 comments on commit 2731cc4

Please sign in to comment.