Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions csharp/.changeset/add-pinned-types-decorator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'Foundation.Data.Doublets.Cli': minor
---

Added `IPinnedTypes` and `PinnedTypesDecorator`, and composed pinned type support into `NamedTypesDecorator`.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void NamedTypesDecorator_ImplementsILinks()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

Assert.True(decorator is ILinks<uint>);
});
}
Expand All @@ -61,8 +61,51 @@ public void NamedTypesDecorator_ImplementsINamedTypes()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);


Assert.True(decorator is INamedTypes<uint>);
});
}

[Fact]
public void NamedTypesDecorator_ImplementsIPinnedTypes()
{
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

Assert.True(decorator is IPinnedTypes<uint>);
});
}

[Fact]
public void NamedTypesDecorator_UsesProvidedPinnedTypesDecorator()
{
RunTestWithLinks(links =>
{
var pinnedTypesDecorator = new PinnedTypesDecorator<uint>(links);
var decorator = new NamedTypesDecorator<uint>(pinnedTypesDecorator, _tempNamesDbPath);

Assert.Same(pinnedTypesDecorator, decorator.PinnedTypesDecorator);
Assert.True(decorator is ILinks<uint>);
Assert.True(decorator is INamedTypes<uint>);
Assert.True(decorator is IPinnedTypes<uint>);
});
}

[Fact]
public void NamedTypesDecorator_CanEnumeratePinnedTypes()
{
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var types = decorator.Take(3).ToArray();
var (type1, type2, type3) = decorator;

Assert.Equal(new uint[] { 1, 2, 3 }, types);
Assert.Equal(1u, type1);
Assert.Equal(2u, type2);
Assert.Equal(3u, type3);
});
}

Expand All @@ -72,19 +115,19 @@ public void NamedTypesDecorator_CanSetAndGetNames()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var link1 = decorator.GetOrCreate(10u, 20u);
var link2 = decorator.GetOrCreate(30u, 40u);

var nameLink1 = decorator.SetName(link1, "TestLink1");
var nameLink2 = decorator.SetName(link2, "TestLink2");

Assert.NotEqual(links.Constants.Null, nameLink1);
Assert.NotEqual(links.Constants.Null, nameLink2);

var retrievedName1 = decorator.GetName(link1);
var retrievedName2 = decorator.GetName(link2);

Assert.Equal("TestLink1", retrievedName1);
Assert.Equal("TestLink2", retrievedName2);
});
Expand All @@ -96,12 +139,12 @@ public void NamedTypesDecorator_CanGetLinkByName()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var link = decorator.GetOrCreate(50u, 60u);
decorator.SetName(link, "UniqueTestName");

var retrievedLink = decorator.GetByName("UniqueTestName");

Assert.Equal(link, retrievedLink);
});
}
Expand All @@ -112,18 +155,18 @@ public void NamedTypesDecorator_CanRemoveNames()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var link = decorator.GetOrCreate(70u, 80u);
decorator.SetName(link, "TemporaryName");

var nameBeforeRemoval = decorator.GetName(link);
Assert.Equal("TemporaryName", nameBeforeRemoval);

decorator.RemoveName(link);

var nameAfterRemoval = decorator.GetName(link);
Assert.Null(nameAfterRemoval);

var linkByName = decorator.GetByName("TemporaryName");
Assert.Equal(links.Constants.Null, linkByName);
});
Expand All @@ -135,21 +178,21 @@ public void NamedTypesDecorator_CanOverwriteNames()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var link = decorator.GetOrCreate(90u, 100u);
decorator.SetName(link, "FirstName");

var firstRetrievedName = decorator.GetName(link);
Assert.Equal("FirstName", firstRetrievedName);

decorator.SetName(link, "SecondName");

var secondRetrievedName = decorator.GetName(link);
Assert.Equal("SecondName", secondRetrievedName);

var linkByFirstName = decorator.GetByName("FirstName");
Assert.Equal(links.Constants.Null, linkByFirstName);

var linkBySecondName = decorator.GetByName("SecondName");
Assert.Equal(link, linkBySecondName);
});
Expand Down Expand Up @@ -180,15 +223,15 @@ public void NamedTypesDecorator_DeleteRemovesAssociatedNames()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var link = decorator.GetOrCreate(110u, 120u);
decorator.SetName(link, "LinkToDelete");

var nameBeforeDeletion = decorator.GetName(link);
Assert.Equal("LinkToDelete", nameBeforeDeletion);

decorator.Delete(new uint[] { link }, null);

var linkByName = decorator.GetByName("LinkToDelete");
Assert.Equal(links.Constants.Null, linkByName);
});
Expand Down Expand Up @@ -223,10 +266,10 @@ public void NamedTypesDecorator_HandlesNonexistentNames()
RunTestWithLinks(links =>
{
var decorator = new NamedTypesDecorator<uint>(links, _tempNamesDbPath);

var linkByNonexistentName = decorator.GetByName("NonexistentName");
Assert.Equal(links.Constants.Null, linkByNonexistentName);

var nameOfNonexistentLink = decorator.GetName(999999u);
Assert.Null(nameOfNonexistentLink);
});
Expand Down
115 changes: 115 additions & 0 deletions csharp/Foundation.Data.Doublets.Cli.Tests/PinnedTypesDecoratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Platform.Data;
using Platform.Data.Doublets;
using Platform.Data.Doublets.Memory.United.Generic;
using Xunit;

namespace Foundation.Data.Doublets.Cli.Tests
{
public class PinnedTypesDecoratorTests
{
[Fact]
public void Should_Implement_Both_ILinks_And_IPinnedTypes()
{
// Arrange
var tempDbFile = Path.GetTempFileName();
try
{
using var links = new UnitedMemoryLinks<ulong>(tempDbFile);

// Act
var decorator = new PinnedTypesDecorator<ulong>(links);

// Assert - Should implement both interfaces
Assert.IsAssignableFrom<ILinks<ulong>>(decorator);
Assert.IsAssignableFrom<IPinnedTypes<ulong>>(decorator);
}
finally
{
File.Delete(tempDbFile);
}
}

[Fact]
public void Should_Enumerate_PinnedTypes()
{
// Arrange
var tempDbFile = Path.GetTempFileName();
try
{
using var links = new UnitedMemoryLinks<ulong>(tempDbFile);
var decorator = new PinnedTypesDecorator<ulong>(links);
var numberOfTypes = 3;

// Act
var result = new List<ulong>();
foreach (var type in decorator.Take(numberOfTypes))
{
result.Add(type);
}

// Assert
Assert.Equal(numberOfTypes, result.Count);
Assert.Equal(new ulong[] { 1, 2, 3 }, result);
}
finally
{
File.Delete(tempDbFile);
}
}

[Fact]
public void Should_Support_Deconstruction()
{
// Arrange
var tempDbFile = Path.GetTempFileName();
try
{
using var links = new UnitedMemoryLinks<ulong>(tempDbFile);
var decorator = new PinnedTypesDecorator<ulong>(links);
var initialSource = 1UL;

// Pre-create links to ensure they exist
links.GetOrCreate(initialSource, 1UL);
links.GetOrCreate(initialSource, 2UL);
links.GetOrCreate(initialSource, 3UL);

// Act
var (type1, type2, type3) = decorator;

// Assert
Assert.Equal(1UL, type1);
Assert.Equal(2UL, type2);
Assert.Equal(3UL, type3);
}
finally
{
File.Delete(tempDbFile);
}
}

[Fact]
public void Should_Work_As_ILinks_Decorator()
{
// Arrange
var tempDbFile = Path.GetTempFileName();
try
{
using var baseLinks = new UnitedMemoryLinks<ulong>(tempDbFile);
var decorator = new PinnedTypesDecorator<ulong>(baseLinks);

// Act & Assert - Test that it still works as a decorator and properly implements both interfaces
Assert.NotNull(decorator);
Assert.IsAssignableFrom<ILinks<ulong>>(decorator);
Assert.IsAssignableFrom<IPinnedTypes<ulong>>(decorator);
}
finally
{
File.Delete(tempDbFile);
}
}
}
}
32 changes: 27 additions & 5 deletions csharp/Foundation.Data.Doublets.Cli/NamedTypesDecorator.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Platform.Delegates;
using Platform.Memory;
Expand All @@ -6,13 +9,10 @@
using Platform.Data.Doublets.Decorators;
using Platform.Data.Doublets.Memory;
using Platform.Data.Doublets.Memory.United.Generic;
using System;
using System.Linq;
using System.Collections.Generic;

namespace Foundation.Data.Doublets.Cli
{
public class NamedTypesDecorator<TLinkAddress> : LinksDecoratorBase<TLinkAddress>, INamedTypes<TLinkAddress>
public class NamedTypesDecorator<TLinkAddress> : LinksDecoratorBase<TLinkAddress>, INamedTypes<TLinkAddress>, IPinnedTypes<TLinkAddress>
where TLinkAddress : struct,
IUnsignedNumber<TLinkAddress>,
IComparisonOperators<TLinkAddress, TLinkAddress, bool>,
Expand All @@ -21,6 +21,7 @@ public class NamedTypesDecorator<TLinkAddress> : LinksDecoratorBase<TLinkAddress
IMinMaxValue<TLinkAddress>
{
private readonly bool _tracingEnabled;
public readonly PinnedTypesDecorator<TLinkAddress> PinnedTypesDecorator;
public readonly NamedLinks<TLinkAddress> NamedLinks;
public readonly string NamedLinksDatabaseFileName;

Expand All @@ -38,9 +39,15 @@ public static string MakeNamesDatabaseFilename(string databaseFilename)
return namesDatabaseFilename;
}

public NamedTypesDecorator(ILinks<TLinkAddress> links, string namesDatabaseFilename, bool tracingEnabled = false) : base(links)
public NamedTypesDecorator(ILinks<TLinkAddress> links, string namesDatabaseFilename, bool tracingEnabled = false)
: this(new PinnedTypesDecorator<TLinkAddress>(links), namesDatabaseFilename, tracingEnabled)
{
}

public NamedTypesDecorator(PinnedTypesDecorator<TLinkAddress> pinnedTypesDecorator, string namesDatabaseFilename, bool tracingEnabled = false) : base(pinnedTypesDecorator)
{
_tracingEnabled = tracingEnabled;
PinnedTypesDecorator = pinnedTypesDecorator;
if (_tracingEnabled) Console.WriteLine($"[Trace] Constructing NamedTypesDecorator with names DB: {namesDatabaseFilename}");
var namesConstants = new LinksConstants<TLinkAddress>(enableExternalReferencesSupport: true);
var namesMemory = new FileMappedResizableDirectMemory(namesDatabaseFilename, UnitedMemoryLinks<TLinkAddress>.DefaultLinksSizeStep);
Expand All @@ -55,6 +62,21 @@ public NamedTypesDecorator(string databaseFilename, bool tracingEnabled = false)
{
}

public IEnumerator<TLinkAddress> GetEnumerator()
{
return PinnedTypesDecorator.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public void Deconstruct(out TLinkAddress type1, out TLinkAddress type2, out TLinkAddress type3)
{
PinnedTypesDecorator.Deconstruct(out type1, out type2, out type3);
}

public string? GetName(TLinkAddress link)
{
if (_tracingEnabled) Console.WriteLine($"[Trace] GetName called for link: {link}");
Expand Down
Loading
Loading