From 48bff4951149ea96b3fc5ef433bef3f1be4be1a4 Mon Sep 17 00:00:00 2001 From: Cardidi Date: Sun, 16 Mar 2025 02:53:23 +0800 Subject: [PATCH] adjust code namespace with binary data format designed. --- Flawless-Version-Control.sln | 8 +- .../Flawless.Abstract.Test.csproj | 2 +- .../Exceptions/FlawlessException.cs | 0 .../PlatformPathNonManagedException.cs | 0 .../Flawless.Abstract.csproj | 1 + .../HashID.cs | 14 +- .../WorkPath.cs | 0 Flawless.Abstraction/Author.cs | 33 ----- Flawless.Abstraction/IDepotLabel.cs | 11 -- Flawless.Abstraction/IReadonlyRepository.cs | 18 --- Flawless.Abstraction/IRepository.cs | 11 -- Flawless.Abstraction/RepositoryCommit.cs | 21 --- .../BinaryDataFormat/NetworkDepotObject.cs | 108 +++++++++++++++ .../BinaryDataFormat/StandardDepotObject.cs | 131 ++++++++++++++++++ Flawless.Core/Const.cs | 12 ++ Flawless.Core/Flawless.Core.csproj | 13 ++ .../Interface/IReadonlyRepository.cs | 18 +++ Flawless.Core/Interface/IRepositoryCommit.cs | 22 +++ Flawless.Core/Modal/Author.cs | 7 + Flawless.Core/Modal/CommitManifest.cs | 3 + Flawless.Core/Modal/CompressType.cs | 7 + Flawless.Core/Modal/Depot.cs | 24 ++++ Flawless.Core/Modal/DepotFileInfo.cs | 4 + Flawless.Core/Modal/DepotLabel.cs | 6 + 24 files changed, 371 insertions(+), 103 deletions(-) rename {Flawless.Abstraction => Flawless.Abstract}/Exceptions/FlawlessException.cs (100%) rename {Flawless.Abstraction => Flawless.Abstract}/Exceptions/PlatformPathNonManagedException.cs (100%) rename Flawless.Abstraction/Flawless.Abstraction.csproj => Flawless.Abstract/Flawless.Abstract.csproj (78%) rename {Flawless.Abstraction => Flawless.Abstract}/HashID.cs (80%) rename {Flawless.Abstraction => Flawless.Abstract}/WorkPath.cs (100%) delete mode 100644 Flawless.Abstraction/Author.cs delete mode 100644 Flawless.Abstraction/IDepotLabel.cs delete mode 100644 Flawless.Abstraction/IReadonlyRepository.cs delete mode 100644 Flawless.Abstraction/IRepository.cs delete mode 100644 Flawless.Abstraction/RepositoryCommit.cs create mode 100644 Flawless.Core/BinaryDataFormat/NetworkDepotObject.cs create mode 100644 Flawless.Core/BinaryDataFormat/StandardDepotObject.cs create mode 100644 Flawless.Core/Const.cs create mode 100644 Flawless.Core/Flawless.Core.csproj create mode 100644 Flawless.Core/Interface/IReadonlyRepository.cs create mode 100644 Flawless.Core/Interface/IRepositoryCommit.cs create mode 100644 Flawless.Core/Modal/Author.cs create mode 100644 Flawless.Core/Modal/CommitManifest.cs create mode 100644 Flawless.Core/Modal/CompressType.cs create mode 100644 Flawless.Core/Modal/Depot.cs create mode 100644 Flawless.Core/Modal/DepotFileInfo.cs create mode 100644 Flawless.Core/Modal/DepotLabel.cs diff --git a/Flawless-Version-Control.sln b/Flawless-Version-Control.sln index cb390a4..d5acfa6 100644 --- a/Flawless-Version-Control.sln +++ b/Flawless-Version-Control.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flawless.Abstraction", "Flawless.Abstraction\Flawless.Abstraction.csproj", "{2AF2AA78-8AFB-49B7-AE38-842D301A4DDE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flawless.Abstract", "Flawless.Abstract\Flawless.Abstract.csproj", "{2AF2AA78-8AFB-49B7-AE38-842D301A4DDE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flawless.Abstract.Test", "Flawless.Abstract.Test\Flawless.Abstract.Test.csproj", "{5B1CB26D-99F5-491A-B368-7E3552FE67E9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flawless.Core", "Flawless.Core\Flawless.Core.csproj", "{FA8139D0-FBA4-4F17-9017-B446A732D0E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {5B1CB26D-99F5-491A-B368-7E3552FE67E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B1CB26D-99F5-491A-B368-7E3552FE67E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B1CB26D-99F5-491A-B368-7E3552FE67E9}.Release|Any CPU.Build.0 = Release|Any CPU + {FA8139D0-FBA4-4F17-9017-B446A732D0E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA8139D0-FBA4-4F17-9017-B446A732D0E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA8139D0-FBA4-4F17-9017-B446A732D0E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA8139D0-FBA4-4F17-9017-B446A732D0E8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Flawless.Abstract.Test/Flawless.Abstract.Test.csproj b/Flawless.Abstract.Test/Flawless.Abstract.Test.csproj index 44d33b2..1d60ea8 100644 --- a/Flawless.Abstract.Test/Flawless.Abstract.Test.csproj +++ b/Flawless.Abstract.Test/Flawless.Abstract.Test.csproj @@ -17,7 +17,7 @@ - + diff --git a/Flawless.Abstraction/Exceptions/FlawlessException.cs b/Flawless.Abstract/Exceptions/FlawlessException.cs similarity index 100% rename from Flawless.Abstraction/Exceptions/FlawlessException.cs rename to Flawless.Abstract/Exceptions/FlawlessException.cs diff --git a/Flawless.Abstraction/Exceptions/PlatformPathNonManagedException.cs b/Flawless.Abstract/Exceptions/PlatformPathNonManagedException.cs similarity index 100% rename from Flawless.Abstraction/Exceptions/PlatformPathNonManagedException.cs rename to Flawless.Abstract/Exceptions/PlatformPathNonManagedException.cs diff --git a/Flawless.Abstraction/Flawless.Abstraction.csproj b/Flawless.Abstract/Flawless.Abstract.csproj similarity index 78% rename from Flawless.Abstraction/Flawless.Abstraction.csproj rename to Flawless.Abstract/Flawless.Abstract.csproj index 17b910f..f15ec46 100644 --- a/Flawless.Abstraction/Flawless.Abstraction.csproj +++ b/Flawless.Abstract/Flawless.Abstract.csproj @@ -4,6 +4,7 @@ net9.0 enable enable + Flawless.Abstraction diff --git a/Flawless.Abstraction/HashID.cs b/Flawless.Abstract/HashID.cs similarity index 80% rename from Flawless.Abstraction/HashID.cs rename to Flawless.Abstract/HashID.cs index f11f73b..b3ff465 100644 --- a/Flawless.Abstraction/HashID.cs +++ b/Flawless.Abstract/HashID.cs @@ -6,9 +6,9 @@ namespace Flawless.Abstraction; /// An MD5 based hash code storage. /// [Serializable] -public readonly struct HashId : IEquatable +public record struct HashId { - public static HashId Empty { get; } = new(0); + public static HashId Empty => new(0); private readonly UInt128 _hash; @@ -17,16 +17,16 @@ public readonly struct HashId : IEquatable _hash = hash; } + public HashId(ulong upper, ulong lower) + { + _hash = new UInt128(upper, lower); + } + public bool Equals(HashId other) { return _hash == other._hash; } - public override bool Equals(object? obj) - { - return obj is HashId other && Equals(other); - } - public override int GetHashCode() { return _hash.GetHashCode(); diff --git a/Flawless.Abstraction/WorkPath.cs b/Flawless.Abstract/WorkPath.cs similarity index 100% rename from Flawless.Abstraction/WorkPath.cs rename to Flawless.Abstract/WorkPath.cs diff --git a/Flawless.Abstraction/Author.cs b/Flawless.Abstraction/Author.cs deleted file mode 100644 index 013c87a..0000000 --- a/Flawless.Abstraction/Author.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Flawless.Abstraction; - -/// -/// An author setup to indicate who create a depot or identify a depot author when uploading it. -/// -[Serializable] -public readonly struct Author : IEquatable -{ - public readonly string Name; - - public readonly string Email; - - public Author(string name, string email) - { - Name = name; - Email = email; - } - - public bool Equals(Author other) - { - return Name == other.Name && Email == other.Email; - } - - public override bool Equals(object? obj) - { - return obj is Author other && Equals(other); - } - - public override int GetHashCode() - { - return HashCode.Combine(Name, Email); - } -} \ No newline at end of file diff --git a/Flawless.Abstraction/IDepotLabel.cs b/Flawless.Abstraction/IDepotLabel.cs deleted file mode 100644 index 9e97c76..0000000 --- a/Flawless.Abstraction/IDepotLabel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Flawless.Abstraction; - -/// -/// Standardized interface for any platform to describe data block (Not the actual data) in repository. -/// -public interface IDepotLabel -{ - public abstract HashId Id { get; } - - public abstract IEnumerable Dependencies { get; } -} \ No newline at end of file diff --git a/Flawless.Abstraction/IReadonlyRepository.cs b/Flawless.Abstraction/IReadonlyRepository.cs deleted file mode 100644 index 3bcc7fa..0000000 --- a/Flawless.Abstraction/IReadonlyRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Flawless.Abstraction; - -/// -/// Standardized interface to describe a place to store depots and how they connected with each other. -/// -public interface IReadonlyRepository -{ - public bool IsReadonly { get; } - - public IEnumerable GetCommits(); - - public RepositoryCommit? GetCommitById(uint commitId); - - public IAsyncEnumerable GetCommitsAsync(CancellationToken cancellationToken = default); - - public Task GetCommitByIdAsync(uint commitId, CancellationToken cancellationToken = default); - -} \ No newline at end of file diff --git a/Flawless.Abstraction/IRepository.cs b/Flawless.Abstraction/IRepository.cs deleted file mode 100644 index 9b139b8..0000000 --- a/Flawless.Abstraction/IRepository.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Flawless.Abstraction; - -/// -/// Standardized interface to describe a place to store depots and how they connected with each other with write support. -/// -public interface IRepository : IReadonlyRepository -{ - public uint GetActiveCommitId(); - - public Task GetActiveCommitIdAsync(CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/Flawless.Abstraction/RepositoryCommit.cs b/Flawless.Abstraction/RepositoryCommit.cs deleted file mode 100644 index 68cc7b4..0000000 --- a/Flawless.Abstraction/RepositoryCommit.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Flawless.Abstraction; - -public abstract class RepositoryCommit -{ - public abstract IReadonlyRepository Repository { get; } - - public abstract UInt64 Id { get; } - - public abstract Author Author { get; } - - public abstract DateTime CommitTime { get; } - - public abstract string Message { get; } - - public abstract IDepotLabel Depot { get; } - - public abstract RepositoryCommit? GetParentCommit(); - - public abstract RepositoryCommit? GetChildCommit(); - -} \ No newline at end of file diff --git a/Flawless.Core/BinaryDataFormat/NetworkDepotObject.cs b/Flawless.Core/BinaryDataFormat/NetworkDepotObject.cs new file mode 100644 index 0000000..c8c9f20 --- /dev/null +++ b/Flawless.Core/BinaryDataFormat/NetworkDepotObject.cs @@ -0,0 +1,108 @@ +using System.Runtime.InteropServices; + +namespace Flawless.Core.BinaryDataFormat; + +/* Depot Transmission Format Design - Version 1 + * + * We have shrink some layout design and remap fields in order to optimize for networking transmission. + * + * Notice that we have assumed that all data are represent as LITTLE ENDIAN. + * + * Padding with 8 byte width, so: + * + * ------------------------------------------ + * 0 : Version Code + * 1 : Network Transmission Feature + * 2 : Compressing Algorithm Type (CompressType) + * 3 : Checksum Confuser + * 4 : Depot Generate Time + * 5 : ~ + * 6 : ~ + * 7 : ~ + * ------------------------------------------ + * 8 : ~ + * 9 : ~ + * 10 : ~ + * 11 : ~ + * 12 : File Map String Size + * 13 : ~ + * 14 : ~ + * 15 : ~ + * ------------------------------------------ + * 16 : ~ + * 17 : ~ + * 18 : ~ + * 19 : ~ + * 20 : ~ + * 21 : ~ + * 22 : ~ + * 23 : ~ + * ------------------------------------------ + * 24 : ~ + * 25 : ~ + * 26 : ~ + * 27 : ~ + * 28 : Payload Size + * 29 : ~ + * 30 : ~ + * 31 : ~ + * ------------------------------------------ + * 32 : ~ + * 33 : ~ + * 34 : ~ + * 35 : ~ + * 36 : MD5 Checksum (Standard MD5Checksum) + * 37 : ~ + * 38 : ~ + * 39 : ~ + * ------------------------------------------ + * 40 : ~ + * 41 : ~ + * 42 : ~ + * 43 : ~ + * 44 : ~ + * 45 : ~ + * 46 : ~ + * 47 : ~ + * ------------------------------------------ + * 48 : ~ + * 49 : ~ + * 50 : ~ + * 51 : ~ + * 52 : ~ + * ------------------------------------------ + * FILE NAME MAP (STRING IN UTF8) + * ------------------------------------------ + * PAYLOAD + */ + +[Flags] +public enum NetworkTransmissionFeatureFlag: byte +{ + FileMapIsJson = 1 << 0, + FileMapUseCompressionArgument = 1 << 7, +} + +[Serializable, StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 8, Size = 52)] +public struct NetworkDepotHeaderV1 +{ + [FieldOffset(0)] public byte Version; + + [FieldOffset(1)] public NetworkTransmissionFeatureFlag NetworkTransmissionFeature; + + [FieldOffset(2)] public byte CompressType; + + [FieldOffset(3)] public byte Md5Confuser; + + [FieldOffset(4)] public ulong GenerateTime; + + [FieldOffset(12)] public ulong FileMapStringSizeLower; + + [FieldOffset(20)] public ulong FileMapStringSizeUpper; + + [FieldOffset(28)] public ulong PayloadSize; + + [FieldOffset(36)] public ulong Md5ChecksumLower; + + [FieldOffset(44)] public ulong Md5ChecksumUpper; +} diff --git a/Flawless.Core/BinaryDataFormat/StandardDepotObject.cs b/Flawless.Core/BinaryDataFormat/StandardDepotObject.cs new file mode 100644 index 0000000..c03a27b --- /dev/null +++ b/Flawless.Core/BinaryDataFormat/StandardDepotObject.cs @@ -0,0 +1,131 @@ +using System.Runtime.InteropServices; +using Flawless.Core.Modal; + +namespace Flawless.Core.BinaryDataFormat; + +/* Depot File System Format Design - Version 1 + * + * For best accessing performance, consider use checksum as filename. Binary info did not contains file name mapping, so + * use another file to get the file map of this depot. The structure to describe a map has already defined below. + * + * Consider of compability when depot format was updated, we have configure a lots of area as empty. + * + * Notice that we assuming that all data are represent as LITTLE ENDIAN. + * + * Padding with 4 byte width, so: + * + * ------------------------------------------ + * 0 : Magic Number + * 1 : ~ + * 2 : ~ + * 3 : ~ + * ------------------------------------------ + * 4 : MD5 Checksum (Header + Data) + * 5 : ~ + * 6 : ~ + * 7 : ~ + * ------------------------------------------ + * 8 : ~ + * 9 : ~ + * 10 : ~ + * 11 : ~ + * ------------------------------------------ + * 12 : ~ + * 13 : ~ + * 14 : ~ + * 15 : ~ + * ------------------------------------------ + * 16 : ~ + * 17 : ~ + * 18 : ~ + * 19 : ~ + * ------------------------------------------ + * 20 : Version Code + * 21 : Checksum Confuser + * 22 : (Unused) + * 23 : (Unused) + * ------------------------------------------ + * 24 : Depot Generate Time + * 25 : ~ + * 26 : ~ + * 27 : ~ + * ------------------------------------------ + * 28 : ~ + * 29 : ~ + * 30 : ~ + * 31 : ~ + * ------------------------------------------ + * 32 : Compressing Algorithm Type (CompressType) + * 33 : (Preserve) + * 34 : (Preserve) + * 35 : (Preserve) + * ------------------------------------------ + * 36 : (Preserve) + * 37 : (Preserve) + * 38 : (Preserve) + * 39 : (Preserve) + * ------------------------------------------ + * 40 : Payload Size + * 41 : ~ + * 42 : ~ + * 43 : ~ + * ------------------------------------------ + * 44 : ~ + * 45 : ~ + * 46 : ~ + * 47 : ~ + * ------------------------------------------ + * 48 : (Unused) + * 49 : (Unused) + * 50 : (Unused) + * 51 : (Unused) + * ------------------------------------------ + * 52 : (Unused) + * 53 : (Unused) + * 54 : (Unused) + * 55 : (Unused) + * ------------------------------------------ + * 56 : (Unused) + * 57 : (Unused) + * 58 : (Unused) + * 59 : (Unused) + * ------------------------------------------ + * 60 : (Unused) + * 61 : (Unused) + * 62 : (Unused) + * 63 : (Unused) + * ------------------------------------------ + * PAYLOAD + */ + +[Serializable, StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 4, Size = 64)] +public struct StandardDepotHeaderV1 +{ + public const uint FormatMagicNumber = 0xAAAAAAAAu; + + [FieldOffset(0)] public uint MagicNumber; + + [FieldOffset(4)] public ulong Md5ChecksumLower; + + [FieldOffset(12)] public ulong Md5ChecksumUpper; + + [FieldOffset(20)] public byte Version; + + [FieldOffset(21)] public byte Md5Confuser; + + [FieldOffset(22)] public ushort PayloadUnit; + + [FieldOffset(24)] public ulong GenerateTime; + + [FieldOffset(32)] public byte CompressType; + + [FieldOffset(40)] public ulong PayloadSize; +} + +[Serializable] +public struct StandardDepotMapV1 +{ + public uint FileCount; + + public DepotFileInfo[] Files; +} \ No newline at end of file diff --git a/Flawless.Core/Const.cs b/Flawless.Core/Const.cs new file mode 100644 index 0000000..1a31601 --- /dev/null +++ b/Flawless.Core/Const.cs @@ -0,0 +1,12 @@ +namespace Flawless.Core; + +public static class Const +{ + public const string RootDirectory = ".flawless"; + + public static readonly string DepotDirectory = Path.Combine(RootDirectory, "depot"); + + public static readonly string CommitDirectory = Path.Combine(RootDirectory, "commit"); + + public static readonly string TrackerFile = Path.Combine(RootDirectory, "tracker"); +} \ No newline at end of file diff --git a/Flawless.Core/Flawless.Core.csproj b/Flawless.Core/Flawless.Core.csproj new file mode 100644 index 0000000..8f02b57 --- /dev/null +++ b/Flawless.Core/Flawless.Core.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/Flawless.Core/Interface/IReadonlyRepository.cs b/Flawless.Core/Interface/IReadonlyRepository.cs new file mode 100644 index 0000000..a53b2c1 --- /dev/null +++ b/Flawless.Core/Interface/IReadonlyRepository.cs @@ -0,0 +1,18 @@ +namespace Flawless.Core.Interface; + +/// +/// Standardized interface to describe a place to store depots and how they connected with each other. +/// +public interface IReadonlyRepository +{ + public bool IsReadonly { get; } + + public IEnumerable GetCommits(); + + public IRepositoryCommit? GetCommitById(uint commitId); + + public IAsyncEnumerable GetCommitsAsync(CancellationToken cancellationToken = default); + + public Task GetCommitByIdAsync(uint commitId, CancellationToken cancellationToken = default); + +} \ No newline at end of file diff --git a/Flawless.Core/Interface/IRepositoryCommit.cs b/Flawless.Core/Interface/IRepositoryCommit.cs new file mode 100644 index 0000000..694017b --- /dev/null +++ b/Flawless.Core/Interface/IRepositoryCommit.cs @@ -0,0 +1,22 @@ +using Flawless.Core.Modal; + +namespace Flawless.Core.Interface; + +public interface IRepositoryCommit +{ + public IReadonlyRepository Repository { get; } + + public UInt64 CommitId { get; } + + public Author Author { get; } + + public DateTime CommitTime { get; } + + public string Message { get; } + + public IRepositoryCommit? GetParentCommit(); + + public IRepositoryCommit? GetChildCommit(); + + public ValueTask GetManifest(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/Flawless.Core/Modal/Author.cs b/Flawless.Core/Modal/Author.cs new file mode 100644 index 0000000..c4f568a --- /dev/null +++ b/Flawless.Core/Modal/Author.cs @@ -0,0 +1,7 @@ +namespace Flawless.Core.Modal; + +/// +/// An author setup to indicate who create a depot or identify a depot author when uploading it. +/// +[Serializable] +public record struct Author(string Name, string Email); \ No newline at end of file diff --git a/Flawless.Core/Modal/CommitManifest.cs b/Flawless.Core/Modal/CommitManifest.cs new file mode 100644 index 0000000..b6c2a02 --- /dev/null +++ b/Flawless.Core/Modal/CommitManifest.cs @@ -0,0 +1,3 @@ +namespace Flawless.Core.Modal; + +public record class CommitManifest(ulong ManifestId, DepotLabel Depot, string[] FilePaths); \ No newline at end of file diff --git a/Flawless.Core/Modal/CompressType.cs b/Flawless.Core/Modal/CompressType.cs new file mode 100644 index 0000000..6ccc80c --- /dev/null +++ b/Flawless.Core/Modal/CompressType.cs @@ -0,0 +1,7 @@ +namespace Flawless.Core.Modal; + +public enum CompressType: byte +{ + Raw = 0, + Gzip = 1, +} \ No newline at end of file diff --git a/Flawless.Core/Modal/Depot.cs b/Flawless.Core/Modal/Depot.cs new file mode 100644 index 0000000..b342aec --- /dev/null +++ b/Flawless.Core/Modal/Depot.cs @@ -0,0 +1,24 @@ +using Flawless.Abstraction; + +namespace Flawless.Core.Modal; + +public class Depot +{ + public string RawDataPath { get; } + + public HashId DepotHash { get; } + + public byte Version { get; } + + public byte ChecksumConfuser { get; } + + public DateTime GenerateTime { get; } + + public CompressType CompressType { get; } + + public ulong PayloadSize { get; } + + public uint FileCount { get; } + + public DepotFileInfo[] Files { get; } +} \ No newline at end of file diff --git a/Flawless.Core/Modal/DepotFileInfo.cs b/Flawless.Core/Modal/DepotFileInfo.cs new file mode 100644 index 0000000..eb9831b --- /dev/null +++ b/Flawless.Core/Modal/DepotFileInfo.cs @@ -0,0 +1,4 @@ +namespace Flawless.Core.Modal; + +[Serializable] +public record struct DepotFileInfo(ulong Size, ulong Offset, string Path); \ No newline at end of file diff --git a/Flawless.Core/Modal/DepotLabel.cs b/Flawless.Core/Modal/DepotLabel.cs new file mode 100644 index 0000000..1f42ced --- /dev/null +++ b/Flawless.Core/Modal/DepotLabel.cs @@ -0,0 +1,6 @@ +using Flawless.Abstraction; + +namespace Flawless.Core.Modal; + +[Serializable] +public record struct DepotLabel(HashId Id, HashId[] Baselines); \ No newline at end of file