From c4b6181a6ecd50dc9032b37daba1f6fda6459be0 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Wed, 1 Nov 2023 23:39:30 +0200 Subject: [PATCH 01/10] Added IHasRandomId I'm (not) sorry --- .../IHasRandomId.cs | 11 ++++++ .../SampleValueObjectGuid.cs | 16 +++++++++ .../SampleValueObjectInt.cs | 17 +++++++++ ...ueObject.cs => SampleValueObjectString.cs} | 8 ++--- .../ValueObjectIncrementalSourceGenerator.cs | 36 +++++++++++++++++++ ...ueObjectIncrementalSourceGeneratorTests.cs | 1 + 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/TransparentValueObjects.Augments/IHasRandomId.cs create mode 100644 src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs create mode 100644 src/TransparentValueObjects.Sample/SampleValueObjectInt.cs rename src/TransparentValueObjects.Sample/{SampleValueObject.cs => SampleValueObjectString.cs} (54%) diff --git a/src/TransparentValueObjects.Augments/IHasRandomId.cs b/src/TransparentValueObjects.Augments/IHasRandomId.cs new file mode 100644 index 0000000..136fb0c --- /dev/null +++ b/src/TransparentValueObjects.Augments/IHasRandomId.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; + +namespace TransparentValueObjects.Augments; + +public interface IHasRandomId + where TValueObject : IValueObject + where TValue : unmanaged + where TRandom : Random +{ + public static abstract TValueObject NewRandomId(); +} diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs new file mode 100644 index 0000000..1ed6c52 --- /dev/null +++ b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using TransparentValueObjects.Augments; +using TransparentValueObjects.Generated; + +namespace TransparentValueObjects.Sample; + +[ValueObject] +public readonly partial struct SampleValueObjectGuid : + IHasDefaultValue, + IHasDefaultEqualityComparer, + IHasRandomId +{ + public static SampleValueObjectGuid DefaultValue => From(Guid.Empty); + public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; +} diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs new file mode 100644 index 0000000..a2584e8 --- /dev/null +++ b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using TransparentValueObjects.Augments; +using TransparentValueObjects.Generated; + +namespace TransparentValueObjects.Sample; + +[ValueObject] +public readonly partial struct SampleValueObjectInt : + IHasDefaultValue, + IHasDefaultEqualityComparer, + IHasRandomId +{ + public static SampleValueObjectInt DefaultValue => From(0); + public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; +} diff --git a/src/TransparentValueObjects.Sample/SampleValueObject.cs b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs similarity index 54% rename from src/TransparentValueObjects.Sample/SampleValueObject.cs rename to src/TransparentValueObjects.Sample/SampleValueObjectString.cs index 4c6a10d..bf5d49a 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObject.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs @@ -6,10 +6,10 @@ namespace TransparentValueObjects.Sample; [ValueObject] -public readonly partial struct SampleValueObject : - IHasDefaultValue, - IHasDefaultEqualityComparer +public readonly partial struct SampleValueObjectString : + IHasDefaultValue, + IHasDefaultEqualityComparer { - public static SampleValueObject DefaultValue => From("Hello World!"); + public static SampleValueObjectString DefaultValue => From("Hello World!"); public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase; } diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index 047dad0..af10bab 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -19,6 +19,7 @@ public class ValueObjectIncrementalSourceGenerator : IIncrementalGenerator private const string ValueObjectInterfaceName = "IValueObject"; private const string HasDefaultValueInterfaceName = "IHasDefaultValue"; private const string HasDefaultEqualityComparerInterfaceName = "IHasDefaultEqualityComparer"; + private const string HasRandomIdInterfaceName = "IHasRandomId"; private const string AttributeSourceCode = $$""" @@ -158,6 +159,15 @@ private static void Generate(SourceProductionContext context, Compilation compil if (innerValueTypeName == "global::System.Guid") AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); + + // Equals methods from interfaces and base object + if (GetAugment(valueObjectInterfaces, HasRandomIdInterfaceName) is { } randomIdAugmentTypeSymbol) + { + var randomType = randomIdAugmentTypeSymbol.TypeArguments[2]; + var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; + var isUnamanged = innerValueTypeSymbol.IsUnmanagedType; + AddRandomIdMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, isUnamanged); + } } context.AddSource($"{valueObjectTypeName}.g.cs", SourceText.From(cw.ToString(), Encoding.UTF8)); @@ -178,6 +188,11 @@ private static void Generate(SourceProductionContext context, Compilation compil ); } + private static INamedTypeSymbol? GetAugment(ImmutableArray existingInterfaces, string augmentName) + { + return existingInterfaces.FirstOrDefault(x => x.Name == augmentName && x.ContainingNamespace.ToDisplayString() == AugmentedNamespace); + } + private static bool HasAugment(ImmutableArray existingInterfaces, string augmentName) { return existingInterfaces.Any(x => x.Name == augmentName && x.ContainingNamespace.ToDisplayString() == AugmentedNamespace); @@ -346,6 +361,27 @@ public static void AddGuidSpecificCode( cw.AppendLine(); } + public static void AddRandomIdMethod( + CodeWriter cw, + string valueObjectTypeName, + string innerValueTypeName, + string randomTypeName, + bool isInnerValueUnamanged) + { + if (!isInnerValueUnamanged) return; + + cw.AppendLine($"public static {valueObjectTypeName} NewRandomId()"); + using (cw.AddBlock()) + { + cw.AppendLine($"var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{innerValueTypeName}>();"); + cw.AppendLine($"var random = new {randomTypeName}();"); + cw.AppendLine("global::System.Span bytes = stackalloc byte[size];"); + cw.AppendLine("random.NextBytes(bytes);"); + cw.AppendLine($"var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];"); + cw.AppendLine($"return {valueObjectTypeName}.From(id);"); + } + } + private readonly struct Target : IEquatable { public readonly StructDeclarationSyntax Syntax; diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs index 1644df1..6d906d8 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs @@ -18,6 +18,7 @@ namespace TestNamespace; public readonly partial struct SampleValueObject : TransparentValueObjects.Augments.IHasDefaultValue TransparentValueObjects.Augments.IHasDefaultEqualityComparer + TransparentValueObjects.Augments.IHasDefaultEqualityComparer { public static SampleValueObject GetDefaultValue() => From("Hello World!"); public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase; From 574d45def2d0c52c8938304377f275f1e695f091 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Wed, 1 Nov 2023 23:50:48 +0200 Subject: [PATCH 02/10] Renamed RandomId to RandomValue --- .../{IHasRandomId.cs => IHasRandomValue.cs} | 4 ++-- .../SampleValueObjectGuid.cs | 2 +- .../SampleValueObjectInt.cs | 2 +- .../ValueObjectIncrementalSourceGenerator.cs | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) rename src/TransparentValueObjects.Augments/{IHasRandomId.cs => IHasRandomValue.cs} (51%) diff --git a/src/TransparentValueObjects.Augments/IHasRandomId.cs b/src/TransparentValueObjects.Augments/IHasRandomValue.cs similarity index 51% rename from src/TransparentValueObjects.Augments/IHasRandomId.cs rename to src/TransparentValueObjects.Augments/IHasRandomValue.cs index 136fb0c..d029ac4 100644 --- a/src/TransparentValueObjects.Augments/IHasRandomId.cs +++ b/src/TransparentValueObjects.Augments/IHasRandomValue.cs @@ -2,10 +2,10 @@ namespace TransparentValueObjects.Augments; -public interface IHasRandomId +public interface IHasRandomValue where TValueObject : IValueObject where TValue : unmanaged where TRandom : Random { - public static abstract TValueObject NewRandomId(); + public static abstract TValueObject NewRandomValue(); } diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs index 1ed6c52..6e0aef2 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs @@ -9,7 +9,7 @@ namespace TransparentValueObjects.Sample; public readonly partial struct SampleValueObjectGuid : IHasDefaultValue, IHasDefaultEqualityComparer, - IHasRandomId + IHasRandomValue { public static SampleValueObjectGuid DefaultValue => From(Guid.Empty); public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs index a2584e8..275fed5 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs @@ -10,7 +10,7 @@ namespace TransparentValueObjects.Sample; public readonly partial struct SampleValueObjectInt : IHasDefaultValue, IHasDefaultEqualityComparer, - IHasRandomId + IHasRandomValue { public static SampleValueObjectInt DefaultValue => From(0); public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index af10bab..1df18a2 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -19,7 +19,7 @@ public class ValueObjectIncrementalSourceGenerator : IIncrementalGenerator private const string ValueObjectInterfaceName = "IValueObject"; private const string HasDefaultValueInterfaceName = "IHasDefaultValue"; private const string HasDefaultEqualityComparerInterfaceName = "IHasDefaultEqualityComparer"; - private const string HasRandomIdInterfaceName = "IHasRandomId"; + private const string HasRandomValueInterfaceName = "IHasRandomValue"; private const string AttributeSourceCode = $$""" @@ -160,13 +160,13 @@ private static void Generate(SourceProductionContext context, Compilation compil if (innerValueTypeName == "global::System.Guid") AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); - // Equals methods from interfaces and base object - if (GetAugment(valueObjectInterfaces, HasRandomIdInterfaceName) is { } randomIdAugmentTypeSymbol) + // The NewRandomValue + if (GetAugment(valueObjectInterfaces, HasRandomValueInterfaceName) is { } randomIdAugmentTypeSymbol) { var randomType = randomIdAugmentTypeSymbol.TypeArguments[2]; var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; var isUnamanged = innerValueTypeSymbol.IsUnmanagedType; - AddRandomIdMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, isUnamanged); + AddRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, isUnamanged); } } @@ -361,7 +361,7 @@ public static void AddGuidSpecificCode( cw.AppendLine(); } - public static void AddRandomIdMethod( + public static void AddRandomValueMethod( CodeWriter cw, string valueObjectTypeName, string innerValueTypeName, @@ -370,7 +370,7 @@ public static void AddRandomIdMethod( { if (!isInnerValueUnamanged) return; - cw.AppendLine($"public static {valueObjectTypeName} NewRandomId()"); + cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue()"); using (cw.AddBlock()) { cw.AppendLine($"var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{innerValueTypeName}>();"); From 5226577955ba5b52ad42ba8f8115463b97628d53 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Wed, 1 Nov 2023 23:52:27 +0200 Subject: [PATCH 03/10] Foolproofing --- .../ValueObjectIncrementalSourceGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index 1df18a2..33fdf80 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -161,7 +161,7 @@ private static void Generate(SourceProductionContext context, Compilation compil AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); // The NewRandomValue - if (GetAugment(valueObjectInterfaces, HasRandomValueInterfaceName) is { } randomIdAugmentTypeSymbol) + if (GetAugment(valueObjectInterfaces, HasRandomValueInterfaceName) is { TypeArguments.Length: 3 } randomIdAugmentTypeSymbol) { var randomType = randomIdAugmentTypeSymbol.TypeArguments[2]; var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; From 87f7af0942c282962fb7d59c13f5ea4f01497c23 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 Nov 2023 01:33:18 +0200 Subject: [PATCH 04/10] Replaced IHasRandomValue with IHasRandomValueGenerator Added an unmanaged implementation IHasUnmanagedRandomValueGenerator --- .../IHasRandomValue.cs | 11 ------ .../IHasRandomValueGenerator.cs | 11 ++++++ .../IHasUnmanagedRandomValueGenerator.cs | 9 +++++ .../SampleValueObjectGuid.cs | 3 +- .../SampleValueObjectInt.cs | 3 +- .../SampleValueObjectString.cs | 12 +++++- .../ValueObjectIncrementalSourceGenerator.cs | 39 +++++++++++++------ 7 files changed, 61 insertions(+), 27 deletions(-) delete mode 100644 src/TransparentValueObjects.Augments/IHasRandomValue.cs create mode 100644 src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs create mode 100644 src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs diff --git a/src/TransparentValueObjects.Augments/IHasRandomValue.cs b/src/TransparentValueObjects.Augments/IHasRandomValue.cs deleted file mode 100644 index d029ac4..0000000 --- a/src/TransparentValueObjects.Augments/IHasRandomValue.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace TransparentValueObjects.Augments; - -public interface IHasRandomValue - where TValueObject : IValueObject - where TValue : unmanaged - where TRandom : Random -{ - public static abstract TValueObject NewRandomValue(); -} diff --git a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs new file mode 100644 index 0000000..6e761bf --- /dev/null +++ b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs @@ -0,0 +1,11 @@ +namespace TransparentValueObjects.Augments; + +public interface IHasRandomValueGenerator + where TValueObject : IValueObject + where TValue : notnull + where TRandom : Random +{ + public static abstract Func GenerateRandomValue { get; } + + public static abstract TValueObject NewRandomValue(TRandom? random); +} diff --git a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs new file mode 100644 index 0000000..4993d1a --- /dev/null +++ b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs @@ -0,0 +1,9 @@ +namespace TransparentValueObjects.Augments; + +public interface IHasUnmanagedRandomValueGenerator : IHasRandomValueGenerator + where TValueObject : IValueObject + where TValue : unmanaged + where TRandom : Random +{ + +} diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs index 6e0aef2..3513237 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs @@ -9,8 +9,9 @@ namespace TransparentValueObjects.Sample; public readonly partial struct SampleValueObjectGuid : IHasDefaultValue, IHasDefaultEqualityComparer, - IHasRandomValue + IHasRandomValueGenerator { public static SampleValueObjectGuid DefaultValue => From(Guid.Empty); public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; + public static Func GenerateRandomValue => _ => From(Guid.NewGuid()); } diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs index 275fed5..1d7d032 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using TransparentValueObjects.Augments; using TransparentValueObjects.Generated; @@ -10,7 +9,7 @@ namespace TransparentValueObjects.Sample; public readonly partial struct SampleValueObjectInt : IHasDefaultValue, IHasDefaultEqualityComparer, - IHasRandomValue + IHasUnmanagedRandomValueGenerator { public static SampleValueObjectInt DefaultValue => From(0); public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs index bf5d49a..8a90a0d 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs @@ -8,8 +8,18 @@ namespace TransparentValueObjects.Sample; [ValueObject] public readonly partial struct SampleValueObjectString : IHasDefaultValue, - IHasDefaultEqualityComparer + IHasDefaultEqualityComparer, + IHasRandomValueGenerator { public static SampleValueObjectString DefaultValue => From("Hello World!"); public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase; + public static Func GenerateRandomValue => random => + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return From(string.Create(10, random ?? new Random(), static (span, random) => + { + for (var i = 0; i < span.Length; i++) + span[i] = chars[random.Next(0, chars.Length)]; + })); + }; } diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index 33fdf80..2afd3ae 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -19,7 +19,8 @@ public class ValueObjectIncrementalSourceGenerator : IIncrementalGenerator private const string ValueObjectInterfaceName = "IValueObject"; private const string HasDefaultValueInterfaceName = "IHasDefaultValue"; private const string HasDefaultEqualityComparerInterfaceName = "IHasDefaultEqualityComparer"; - private const string HasRandomValueInterfaceName = "IHasRandomValue"; + private const string HasRandomValueGeneratorInterfaceName = "IHasRandomValueGenerator"; + private const string HasUnmanagedRandomValueGeneratorInterfaceName = "IHasUnmanagedRandomValueGenerator"; private const string AttributeSourceCode = $$""" @@ -161,12 +162,18 @@ private static void Generate(SourceProductionContext context, Compilation compil AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); // The NewRandomValue - if (GetAugment(valueObjectInterfaces, HasRandomValueInterfaceName) is { TypeArguments.Length: 3 } randomIdAugmentTypeSymbol) + if (GetAugment(valueObjectInterfaces, HasRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } randomAugmentTypeSymbol) { - var randomType = randomIdAugmentTypeSymbol.TypeArguments[2]; + var randomType = randomAugmentTypeSymbol.TypeArguments[2]; var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; - var isUnamanged = innerValueTypeSymbol.IsUnmanagedType; - AddRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, isUnamanged); + AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); + } + if (GetAugment(valueObjectInterfaces, HasUnmanagedRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } uRandomAugmentTypeSymbol) + { + var randomType = uRandomAugmentTypeSymbol.TypeArguments[2]; + var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; + AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); + AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); } } @@ -361,25 +368,33 @@ public static void AddGuidSpecificCode( cw.AppendLine(); } - public static void AddRandomValueMethod( + public static void AddRandomValueMethod(CodeWriter cw, string valueObjectTypeName, string randomTypeName) + { + cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue({randomTypeName}? random)"); + using (cw.AddBlock()) + { + cw.AppendLine("var randomValue = GenerateRandomValue(random);"); + cw.AppendLine("return randomValue;"); + } + } + + public static void AddUnmanagedRandomValueMethod( CodeWriter cw, string valueObjectTypeName, string innerValueTypeName, - string randomTypeName, - bool isInnerValueUnamanged) + string randomTypeName) { - if (!isInnerValueUnamanged) return; - - cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue()"); + cw.AppendLine($"public static global::System.Func<{randomTypeName}?, {valueObjectTypeName}> GenerateRandomValue => random =>"); using (cw.AddBlock()) { + cw.AppendLine($"random ??= new {randomTypeName}();"); cw.AppendLine($"var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{innerValueTypeName}>();"); - cw.AppendLine($"var random = new {randomTypeName}();"); cw.AppendLine("global::System.Span bytes = stackalloc byte[size];"); cw.AppendLine("random.NextBytes(bytes);"); cw.AppendLine($"var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];"); cw.AppendLine($"return {valueObjectTypeName}.From(id);"); } + cw.Append(";"); } private readonly struct Target : IEquatable From 0673ac230bb6a9936f52fd7f7f0360e966d414ba Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 Nov 2023 12:19:51 +0200 Subject: [PATCH 05/10] Added tests --- ...ueObjectIncrementalSourceGeneratorTests.cs | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs index 6d906d8..c2489dd 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs @@ -19,9 +19,19 @@ namespace TestNamespace; TransparentValueObjects.Augments.IHasDefaultValue TransparentValueObjects.Augments.IHasDefaultEqualityComparer TransparentValueObjects.Augments.IHasDefaultEqualityComparer + TransparentValueObjects.Augments.IHasRandomValueGenerator { public static SampleValueObject GetDefaultValue() => From("Hello World!"); public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase; + public static Func GenerateRandomValue => random => + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return From(string.Create(10, random ?? new Random(), static (span, random) => + { + for (var i = 0; i < span.Length; i++) + span[i] = chars[random.Next(0, chars.Length)]; + })); + }; } """; @@ -34,16 +44,17 @@ namespace TestNamespace; [global::System.Diagnostics.DebuggerDisplay("{Value}")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")] readonly partial struct SampleValueObject : - global::TransparentValueObjects.Augments.IValueObject, + global::TransparentValueObjects.Augments.IValueObject, global::System.IEquatable, - global::System.IEquatable + global::System.IEquatable, + global::System.IComparable { public readonly global::System.String Value; - public SampleValueObject() - { - Value = DefaultValue.Value; - } + public SampleValueObject() + { + Value = DefaultValue.Value; + } private SampleValueObject(global::System.String value) { @@ -79,6 +90,13 @@ public override bool Equals(object? obj) public static explicit operator SampleValueObject(global::System.String value) => From(value); public static explicit operator global::System.String(SampleValueObject value) => value.Value; +public global::System.Int32 CompareTo(SampleValueObject other) => Value.CompareTo(other); + public static SampleValueObject NewRandomValue(global::.Random? random) + { + var randomValue = GenerateRandomValue(random); + return randomValue; + } + } """; @@ -230,6 +248,54 @@ public override bool Equals(object? obj) NormalizeEquals(cw.ToString(), output); } + [Fact] + public void Test_AddRandomValueMethod() + { + const string valueObjectTypeName = "MyValueObject"; + const string randomTypeName = "System.Random"; + const string output = + $$""" + public static {{valueObjectTypeName}} NewRandomValue({{randomTypeName}}? random) + { + var randomValue = GenerateRandomValue(random); + return randomValue; + } + """; + + var cw = new CodeWriter(); + ValueObjectIncrementalSourceGenerator.AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); + + NormalizeEquals(cw.ToString(), output); + } + + [Fact] + public void Test_AddUnmanagedRandomValueMethod() + { + const string valueObjectTypeName = "MyValueObject"; + const string innerValueTypeName = "System.Int32"; + const string randomTypeName = "System.Random"; + const string output = +$$""" +public static global::System.Func<{{randomTypeName}}?, {{valueObjectTypeName}}> GenerateRandomValue => random => +{ + random ??= new {{randomTypeName}}(); + var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{{innerValueTypeName}}>(); + global::System.Span bytes = stackalloc byte[size]; + random.NextBytes(bytes); + var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0]; + return {{valueObjectTypeName}}.From(id); +} + +; +"""; + + var cw = new CodeWriter(); + ValueObjectIncrementalSourceGenerator.AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); + + var t = cw.ToString(); + NormalizeEquals(cw.ToString(), output); + } + [Fact] public void Test_AddEqualityOperators() { From 0a21fbb341c501b4c807540df46377fae1b0464b Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 Nov 2023 12:27:38 +0200 Subject: [PATCH 06/10] Changed method position --- .../ValueObjectIncrementalSourceGenerator.cs | 12 ++++++------ .../ValueObjectIncrementalSourceGeneratorTests.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index 2afd3ae..ba79fe5 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -155,12 +155,6 @@ private static void Generate(SourceProductionContext context, Compilation compil // explicit cast operators AddExplicitCastOperators(cw, valueObjectTypeName, innerValueTypeName); - if (comparableInterfaceTypeSymbol is not null) - ForwardInterface(cw, valueObjectTypeName, comparableInterfaceTypeSymbol); - - if (innerValueTypeName == "global::System.Guid") - AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); - // The NewRandomValue if (GetAugment(valueObjectInterfaces, HasRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } randomAugmentTypeSymbol) { @@ -175,6 +169,12 @@ private static void Generate(SourceProductionContext context, Compilation compil AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); } + + if (comparableInterfaceTypeSymbol is not null) + ForwardInterface(cw, valueObjectTypeName, comparableInterfaceTypeSymbol); + + if (innerValueTypeName == "global::System.Guid") + AddGuidSpecificCode(cw, valueObjectTypeName, innerValueTypeName); } context.AddSource($"{valueObjectTypeName}.g.cs", SourceText.From(cw.ToString(), Encoding.UTF8)); diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs index c2489dd..4cc3f85 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs @@ -90,13 +90,13 @@ public override bool Equals(object? obj) public static explicit operator SampleValueObject(global::System.String value) => From(value); public static explicit operator global::System.String(SampleValueObject value) => value.Value; -public global::System.Int32 CompareTo(SampleValueObject other) => Value.CompareTo(other); public static SampleValueObject NewRandomValue(global::.Random? random) { var randomValue = GenerateRandomValue(random); return randomValue; } +public global::System.Int32 CompareTo(SampleValueObject other) => Value.CompareTo(other); } """; From d2bb584ba1fc720a3d653b3ec710aba49632f866 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 2 Nov 2023 12:33:26 +0200 Subject: [PATCH 07/10] Changed method position --- ...ueObjectIncrementalSourceGeneratorTests.cs | 83 +++++++++---------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs index 4cc3f85..c58ba35 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests.cs @@ -249,89 +249,88 @@ public override bool Equals(object? obj) } [Fact] - public void Test_AddRandomValueMethod() + public void Test_AddEqualityOperators() { const string valueObjectTypeName = "MyValueObject"; - const string randomTypeName = "System.Random"; + const string innerValueTypeName = "string"; const string output = - $$""" - public static {{valueObjectTypeName}} NewRandomValue({{randomTypeName}}? random) - { - var randomValue = GenerateRandomValue(random); - return randomValue; - } - """; +$$""" +public static bool operator ==({{valueObjectTypeName}} left, {{valueObjectTypeName}} right) => left.Equals(right); +public static bool operator !=({{valueObjectTypeName}} left, {{valueObjectTypeName}} right) => !left.Equals(right); + +public static bool operator ==({{valueObjectTypeName}} left, {{innerValueTypeName}} right) => left.Equals(right); +public static bool operator !=({{valueObjectTypeName}} left, {{innerValueTypeName}} right) => !left.Equals(right); + +public static bool operator ==({{innerValueTypeName}} left, {{valueObjectTypeName}} right) => right.Equals(left); +public static bool operator !=({{innerValueTypeName}} left, {{valueObjectTypeName}} right) => !right.Equals(left); +"""; var cw = new CodeWriter(); - ValueObjectIncrementalSourceGenerator.AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); + ValueObjectIncrementalSourceGenerator.AddEqualityOperators(cw, valueObjectTypeName, innerValueTypeName); NormalizeEquals(cw.ToString(), output); } [Fact] - public void Test_AddUnmanagedRandomValueMethod() + public void Test_AddExplicitCastOperators() { const string valueObjectTypeName = "MyValueObject"; - const string innerValueTypeName = "System.Int32"; - const string randomTypeName = "System.Random"; + const string innerValueTypeName = "string"; const string output = $$""" -public static global::System.Func<{{randomTypeName}}?, {{valueObjectTypeName}}> GenerateRandomValue => random => -{ - random ??= new {{randomTypeName}}(); - var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{{innerValueTypeName}}>(); - global::System.Span bytes = stackalloc byte[size]; - random.NextBytes(bytes); - var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0]; - return {{valueObjectTypeName}}.From(id); -} - -; +public static explicit operator {{valueObjectTypeName}}({{innerValueTypeName}} value) => From(value); +public static explicit operator {{innerValueTypeName}}({{valueObjectTypeName}} value) => value.Value; """; var cw = new CodeWriter(); - ValueObjectIncrementalSourceGenerator.AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); + ValueObjectIncrementalSourceGenerator.AddExplicitCastOperators(cw, valueObjectTypeName, innerValueTypeName); - var t = cw.ToString(); NormalizeEquals(cw.ToString(), output); } [Fact] - public void Test_AddEqualityOperators() + public void Test_AddRandomValueMethod() { const string valueObjectTypeName = "MyValueObject"; - const string innerValueTypeName = "string"; + const string randomTypeName = "System.Random"; const string output = $$""" -public static bool operator ==({{valueObjectTypeName}} left, {{valueObjectTypeName}} right) => left.Equals(right); -public static bool operator !=({{valueObjectTypeName}} left, {{valueObjectTypeName}} right) => !left.Equals(right); - -public static bool operator ==({{valueObjectTypeName}} left, {{innerValueTypeName}} right) => left.Equals(right); -public static bool operator !=({{valueObjectTypeName}} left, {{innerValueTypeName}} right) => !left.Equals(right); - -public static bool operator ==({{innerValueTypeName}} left, {{valueObjectTypeName}} right) => right.Equals(left); -public static bool operator !=({{innerValueTypeName}} left, {{valueObjectTypeName}} right) => !right.Equals(left); +public static {{valueObjectTypeName}} NewRandomValue({{randomTypeName}}? random) +{ + var randomValue = GenerateRandomValue(random); + return randomValue; +} """; var cw = new CodeWriter(); - ValueObjectIncrementalSourceGenerator.AddEqualityOperators(cw, valueObjectTypeName, innerValueTypeName); + ValueObjectIncrementalSourceGenerator.AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); NormalizeEquals(cw.ToString(), output); } [Fact] - public void Test_AddExplicitCastOperators() + public void Test_AddUnmanagedRandomValueMethod() { const string valueObjectTypeName = "MyValueObject"; - const string innerValueTypeName = "string"; + const string innerValueTypeName = "System.Int32"; + const string randomTypeName = "System.Random"; const string output = $$""" -public static explicit operator {{valueObjectTypeName}}({{innerValueTypeName}} value) => From(value); -public static explicit operator {{innerValueTypeName}}({{valueObjectTypeName}} value) => value.Value; +public static global::System.Func<{{randomTypeName}}?, {{valueObjectTypeName}}> GenerateRandomValue => random => +{ + random ??= new {{randomTypeName}}(); + var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{{innerValueTypeName}}>(); + global::System.Span bytes = stackalloc byte[size]; + random.NextBytes(bytes); + var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0]; + return {{valueObjectTypeName}}.From(id); +} + +; """; var cw = new CodeWriter(); - ValueObjectIncrementalSourceGenerator.AddExplicitCastOperators(cw, valueObjectTypeName, innerValueTypeName); + ValueObjectIncrementalSourceGenerator.AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); NormalizeEquals(cw.ToString(), output); } From ecf1c13c9390deb1d2dad6eceff8f242af36d867 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 9 Nov 2023 00:01:32 +0200 Subject: [PATCH 08/10] Updated implementation Removed GenerateRandomValue Added GetRandom --- .../IHasRandomValueGenerator.cs | 6 +- .../IHasUnmanagedRandomValueGenerator.cs | 2 +- .../SampleValueObjectGuid.cs | 2 +- .../SampleValueObjectString.cs | 6 +- .../ValueObjectIncrementalSourceGenerator.cs | 47 ++++++--- .../Augments/HasRandomValueGenerator.cs | 93 ++++++++++++++++++ .../HasRandomValueGenerator_WithRandom.cs | 94 ++++++++++++++++++ .../HasRandomValueGenerator_WithUnmanaged.cs | 94 ++++++++++++++++++ ...omValueGenerator_WithUnmanagedAndRandom.cs | 96 +++++++++++++++++++ 9 files changed, 420 insertions(+), 20 deletions(-) create mode 100644 tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs create mode 100644 tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs create mode 100644 tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs create mode 100644 tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs diff --git a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs index 6e761bf..e2e8576 100644 --- a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs +++ b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs @@ -1,11 +1,11 @@ namespace TransparentValueObjects.Augments; -public interface IHasRandomValueGenerator +public interface IHasRandomValueGenerator where TValueObject : IValueObject where TValue : notnull where TRandom : Random { - public static abstract Func GenerateRandomValue { get; } + public static abstract TRandom GetRandom(); - public static abstract TValueObject NewRandomValue(TRandom? random); + public static abstract TValueObject NewRandomValue(); } diff --git a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs index 4993d1a..4374a50 100644 --- a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs +++ b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs @@ -1,6 +1,6 @@ namespace TransparentValueObjects.Augments; -public interface IHasUnmanagedRandomValueGenerator : IHasRandomValueGenerator +public interface IHasUnmanagedRandomValueGenerator : IHasRandomValueGenerator where TValueObject : IValueObject where TValue : unmanaged where TRandom : Random diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs index 3513237..8785baf 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs @@ -13,5 +13,5 @@ namespace TransparentValueObjects.Sample; { public static SampleValueObjectGuid DefaultValue => From(Guid.Empty); public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default; - public static Func GenerateRandomValue => _ => From(Guid.NewGuid()); + public static Random GetRandom() => Random.Shared; } diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs index 8a90a0d..8bc50fd 100644 --- a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs +++ b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs @@ -13,13 +13,13 @@ namespace TransparentValueObjects.Sample; { public static SampleValueObjectString DefaultValue => From("Hello World!"); public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase; - public static Func GenerateRandomValue => random => + public static SampleValueObjectString NewRandomValue() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - return From(string.Create(10, random ?? new Random(), static (span, random) => + return From(string.Create(10, GetRandom(), static (span, random) => { for (var i = 0; i < span.Length; i++) span[i] = chars[random.Next(0, chars.Length)]; })); - }; + } } diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index 2bac196..f223dba 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -160,14 +160,19 @@ private static void Generate(SourceProductionContext context, Compilation compil { var randomType = randomAugmentTypeSymbol.TypeArguments[2]; var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; - AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); + var hasGetRandomOverride = valueObjectNamedTypeSymbol.GetMembers("GetRandom") + .Any(x => x is IMethodSymbol { ReturnType: var ret, Parameters.Length: 0 } && SymbolEqualityComparer.Default.Equals(ret, randomType)); + var hasNewRandomValueOverride = valueObjectNamedTypeSymbol.GetMembers("NewRandomValue") + .Any(x => x is IMethodSymbol { ReturnType: var ret, Parameters.Length: 0 } && SymbolEqualityComparer.IncludeNullability.Equals(ret, valueObjectNamedTypeSymbol)); + AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName, hasGetRandomOverride, hasNewRandomValueOverride); } if (GetAugment(valueObjectInterfaces, HasUnmanagedRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } uRandomAugmentTypeSymbol) { var randomType = uRandomAugmentTypeSymbol.TypeArguments[2]; var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}"; - AddRandomValueMethod(cw, valueObjectTypeName, randomTypeName); - AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName); + var hasGetRandomOverride = valueObjectNamedTypeSymbol.GetMembers("GetRandom") + .Any(x => x is IMethodSymbol { ReturnType: var ret, Parameters.Length: 0 } && SymbolEqualityComparer.Default.Equals(ret, randomType)); + AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, hasGetRandomOverride); } if (comparableInterfaceTypeSymbol is not null) @@ -368,13 +373,26 @@ public static void AddGuidSpecificCode( cw.AppendLine(); } - public static void AddRandomValueMethod(CodeWriter cw, string valueObjectTypeName, string randomTypeName) + public static void AddRandomValueMethod( + CodeWriter cw, + string valueObjectTypeName, + string randomTypeName, + bool hasGetRandomOverride, + bool hasNewRandomValueOverride) { - cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue({randomTypeName}? random)"); - using (cw.AddBlock()) + if (!hasGetRandomOverride) + { + cw.AppendLine($"public static {randomTypeName} GetRandom() => new {randomTypeName}();"); + } + + if (!hasNewRandomValueOverride) { - cw.AppendLine("var randomValue = GenerateRandomValue(random);"); - cw.AppendLine("return randomValue;"); + cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue()"); + using (cw.AddBlock()) + { + cw.AppendLine("var randomValue = GenerateRandomValue(GetRandom());"); + cw.AppendLine("return randomValue;"); + } } } @@ -382,19 +400,24 @@ public static void AddUnmanagedRandomValueMethod( CodeWriter cw, string valueObjectTypeName, string innerValueTypeName, - string randomTypeName) + string randomTypeName, + bool hasGetRandomOverride) { - cw.AppendLine($"public static global::System.Func<{randomTypeName}?, {valueObjectTypeName}> GenerateRandomValue => random =>"); + if (!hasGetRandomOverride) + { + cw.AppendLine($"public static {randomTypeName} GetRandom() => new {randomTypeName}();"); + } + + cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue()"); using (cw.AddBlock()) { - cw.AppendLine($"random ??= new {randomTypeName}();"); + cw.AppendLine("var random = GetRandom();"); cw.AppendLine($"var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{innerValueTypeName}>();"); cw.AppendLine("global::System.Span bytes = stackalloc byte[size];"); cw.AppendLine("random.NextBytes(bytes);"); cw.AppendLine($"var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];"); cw.AppendLine($"return {valueObjectTypeName}.From(id);"); } - cw.Append(";"); } private readonly struct Target : IEquatable diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs new file mode 100644 index 0000000..07cd851 --- /dev/null +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs @@ -0,0 +1,93 @@ +using Xunit; + +namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments; + +public class HasRandomValueGenerator +{ + private const string Input = +""" +using TransparentValueObjects.Generated; +using TransparentValueObjects.Augments; + +namespace TestNamespace; + +[ValueObject] +public readonly partial struct StringValueObject : IHasRandomValueGenerator +{ + public static StringValueObject DefaultValue => From("Hello World!"); +} +"""; + + private const string Output = +""" +// +#nullable enable +namespace TestNamespace; + +[global::System.Diagnostics.DebuggerDisplay("{Value}")] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")] +readonly partial struct StringValueObject : + global::TransparentValueObjects.Augments.IValueObject, + global::System.IEquatable, + global::System.IEquatable, + global::System.IComparable +{ + public readonly global::System.String Value; + + [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)] + public StringValueObject() + { + throw new global::System.InvalidOperationException($"Use StringValueObject.{nameof(From)} instead."); + } + + private StringValueObject(global::System.String value) + { + Value = value; + } + + public static StringValueObject From(global::System.String value) => new(value); + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public bool Equals(StringValueObject other) => Equals(other.Value); + public bool Equals(global::System.String? other) => Value.Equals(other); + public bool Equals(StringValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value); + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (obj is StringValueObject value) return Equals(value); + if (obj is global::System.String innerValue) return Equals(innerValue); + return false; + } + + public static bool operator ==(StringValueObject left, StringValueObject right) => left.Equals(right); + public static bool operator !=(StringValueObject left, StringValueObject right) => !left.Equals(right); + + public static bool operator ==(StringValueObject left, global::System.String right) => left.Equals(right); + public static bool operator !=(StringValueObject left, global::System.String right) => !left.Equals(right); + + public static bool operator ==(global::System.String left, StringValueObject right) => right.Equals(left); + public static bool operator !=(global::System.String left, StringValueObject right) => !right.Equals(left); + + public static explicit operator StringValueObject(global::System.String value) => From(value); + public static explicit operator global::System.String(StringValueObject value) => value.Value; + + public static global::.Random GetRandom() => new global::.Random(); + public static StringValueObject NewRandomValue() + { + var randomValue = GenerateRandomValue(GetRandom()); + return randomValue; + } + + public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other); +} +"""; + + [Fact] + public void TestAugment() + { + TestHelpers.TestGenerator(Input, "StringValueObject.g.cs", Output); + } +} diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs new file mode 100644 index 0000000..fbb1ec0 --- /dev/null +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs @@ -0,0 +1,94 @@ +using Xunit; + +namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments; + +public class HasRandomValueGenerator_WithRandom +{ + private const string Input = +""" +using TransparentValueObjects.Generated; +using TransparentValueObjects.Augments; + +namespace TestNamespace; + +[ValueObject] +public readonly partial struct StringValueObject : IHasRandomValueGenerator +{ + public static StringValueObject DefaultValue => From("Hello World!"); + + public static Random GetRandom() => new(); +} +"""; + + private const string Output = +""" +// +#nullable enable +namespace TestNamespace; + +[global::System.Diagnostics.DebuggerDisplay("{Value}")] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")] +readonly partial struct StringValueObject : + global::TransparentValueObjects.Augments.IValueObject, + global::System.IEquatable, + global::System.IEquatable, + global::System.IComparable +{ + public readonly global::System.String Value; + + [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)] + public StringValueObject() + { + throw new global::System.InvalidOperationException($"Use StringValueObject.{nameof(From)} instead."); + } + + private StringValueObject(global::System.String value) + { + Value = value; + } + + public static StringValueObject From(global::System.String value) => new(value); + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public bool Equals(StringValueObject other) => Equals(other.Value); + public bool Equals(global::System.String? other) => Value.Equals(other); + public bool Equals(StringValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value); + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (obj is StringValueObject value) return Equals(value); + if (obj is global::System.String innerValue) return Equals(innerValue); + return false; + } + + public static bool operator ==(StringValueObject left, StringValueObject right) => left.Equals(right); + public static bool operator !=(StringValueObject left, StringValueObject right) => !left.Equals(right); + + public static bool operator ==(StringValueObject left, global::System.String right) => left.Equals(right); + public static bool operator !=(StringValueObject left, global::System.String right) => !left.Equals(right); + + public static bool operator ==(global::System.String left, StringValueObject right) => right.Equals(left); + public static bool operator !=(global::System.String left, StringValueObject right) => !right.Equals(left); + + public static explicit operator StringValueObject(global::System.String value) => From(value); + public static explicit operator global::System.String(StringValueObject value) => value.Value; + + public static StringValueObject NewRandomValue() + { + var randomValue = GenerateRandomValue(GetRandom()); + return randomValue; + } + + public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other); +} +"""; + + [Fact] + public void TestAugment() + { + TestHelpers.TestGenerator(Input, "StringValueObject.g.cs", Output); + } +} diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs new file mode 100644 index 0000000..f02c028 --- /dev/null +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs @@ -0,0 +1,94 @@ +using Xunit; + +namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments; + +public class HasRandomValueGenerator_WithUnmanaged +{ + private const string Input = +""" +using TransparentValueObjects.Generated; +using TransparentValueObjects.Augments; + +namespace TestNamespace; + +[ValueObject] +public readonly partial struct Int32ValueObject : IHasUnmanagedRandomValueGenerator { } +"""; + + private const string Output = +""" +// +#nullable enable +namespace TestNamespace; + +[global::System.Diagnostics.DebuggerDisplay("{Value}")] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")] +readonly partial struct Int32ValueObject : + global::TransparentValueObjects.Augments.IValueObject, + global::System.IEquatable, + global::System.IEquatable, + global::System.IComparable +{ + public readonly global::System.String Value; + + [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)] + public Int32ValueObject() + { + throw new global::System.InvalidOperationException($"Use Int32ValueObject.{nameof(From)} instead."); + } + + private Int32ValueObject(global::System.String value) + { + Value = value; + } + + public static Int32ValueObject From(global::System.String value) => new(value); + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public bool Equals(Int32ValueObject other) => Equals(other.Value); + public bool Equals(global::System.String? other) => Value.Equals(other); + public bool Equals(Int32ValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value); + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (obj is Int32ValueObject value) return Equals(value); + if (obj is global::System.String innerValue) return Equals(innerValue); + return false; + } + + public static bool operator ==(Int32ValueObject left, Int32ValueObject right) => left.Equals(right); + public static bool operator !=(Int32ValueObject left, Int32ValueObject right) => !left.Equals(right); + + public static bool operator ==(Int32ValueObject left, global::System.String right) => left.Equals(right); + public static bool operator !=(Int32ValueObject left, global::System.String right) => !left.Equals(right); + + public static bool operator ==(global::System.String left, Int32ValueObject right) => right.Equals(left); + public static bool operator !=(global::System.String left, Int32ValueObject right) => !right.Equals(left); + + public static explicit operator Int32ValueObject(global::System.String value) => From(value); + public static explicit operator global::System.String(Int32ValueObject value) => value.Value; + + public static global::.Random GetRandom() => new global::.Random(); + public static Int32ValueObject NewRandomValue() + { + var random = GetRandom(); + var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf(); + global::System.Span bytes = stackalloc byte[size]; + random.NextBytes(bytes); + var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0]; + return Int32ValueObject.From(id); + } + + public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other); +} +"""; + + [Fact] + public void TestAugment() + { + TestHelpers.TestGenerator(Input, "Int32ValueObject.g.cs", Output); + } +} diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs new file mode 100644 index 0000000..152093c --- /dev/null +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs @@ -0,0 +1,96 @@ +using Xunit; + +namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments; + +public class HasRandomValueGenerator_WithUnmanagedAndRandom +{ + private const string Input = +""" +using TransparentValueObjects.Generated; +using TransparentValueObjects.Augments; + +namespace TestNamespace; + +[ValueObject] +public readonly partial struct Int32ValueObject : IHasUnmanagedRandomValueGenerator +{ + public static Random GetRandom() => Random.Shared; +} +"""; + + private const string Output = +""" +// +#nullable enable +namespace TestNamespace; + +[global::System.Diagnostics.DebuggerDisplay("{Value}")] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")] +readonly partial struct Int32ValueObject : + global::TransparentValueObjects.Augments.IValueObject, + global::System.IEquatable, + global::System.IEquatable, + global::System.IComparable +{ + public readonly global::System.String Value; + + [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)] + public Int32ValueObject() + { + throw new global::System.InvalidOperationException($"Use Int32ValueObject.{nameof(From)} instead."); + } + + private Int32ValueObject(global::System.String value) + { + Value = value; + } + + public static Int32ValueObject From(global::System.String value) => new(value); + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public bool Equals(Int32ValueObject other) => Equals(other.Value); + public bool Equals(global::System.String? other) => Value.Equals(other); + public bool Equals(Int32ValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value); + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (obj is Int32ValueObject value) return Equals(value); + if (obj is global::System.String innerValue) return Equals(innerValue); + return false; + } + + public static bool operator ==(Int32ValueObject left, Int32ValueObject right) => left.Equals(right); + public static bool operator !=(Int32ValueObject left, Int32ValueObject right) => !left.Equals(right); + + public static bool operator ==(Int32ValueObject left, global::System.String right) => left.Equals(right); + public static bool operator !=(Int32ValueObject left, global::System.String right) => !left.Equals(right); + + public static bool operator ==(global::System.String left, Int32ValueObject right) => right.Equals(left); + public static bool operator !=(global::System.String left, Int32ValueObject right) => !right.Equals(left); + + public static explicit operator Int32ValueObject(global::System.String value) => From(value); + public static explicit operator global::System.String(Int32ValueObject value) => value.Value; + + public static Int32ValueObject NewRandomValue() + { + var random = GetRandom(); + var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf(); + global::System.Span bytes = stackalloc byte[size]; + random.NextBytes(bytes); + var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0]; + return Int32ValueObject.From(id); + } + + public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other); +} +"""; + + [Fact] + public void TestAugment() + { + TestHelpers.TestGenerator(Input, "Int32ValueObject.g.cs", Output); + } +} From f4ccee37cd94cfa400835c3d479f1f21b1f3bb89 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 9 Nov 2023 18:26:28 +0200 Subject: [PATCH 09/10] Adapted tests --- .../ValueObjectIncrementalSourceGenerator.cs | 2 +- .../Augments/HasRandomValueGenerator.cs | 23 ++++++++++++++----- .../HasRandomValueGenerator_WithRandom.cs | 23 ++++++++++++++----- .../HasRandomValueGenerator_WithUnmanaged.cs | 17 ++++++++++++++ ...omValueGenerator_WithUnmanagedAndRandom.cs | 17 ++++++++++++++ 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs index d17f5db..22e4aee 100644 --- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs +++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs @@ -420,7 +420,7 @@ public static void AddGuidSpecificCode( cw.AppendLine(); } - public static void AddSystemTextJsonClasses(CodeWriter cw, string valueObjectTypeName, string innerValueTypeName, bool hasDefaultValue) + public static void AddSystemTextJsonClasses(CodeWriter cw, string valueObjectTypeName, string innerValueTypeName, bool hasDefaultValue) { cw.AppendLine("public static global::System.Type SystemTextJsonConverterType => typeof(SystemTextJsonConverter);"); diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs index 07cd851..558a9b7 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs @@ -34,6 +34,8 @@ namespace TestNamespace; { public readonly global::System.String Value; + public static global::System.Type InnerValueType => typeof(global::System.String); + [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)] public StringValueObject() { @@ -75,13 +77,22 @@ public override bool Equals(object? obj) public static explicit operator global::System.String(StringValueObject value) => value.Value; public static global::.Random GetRandom() => new global::.Random(); - public static StringValueObject NewRandomValue() - { - var randomValue = GenerateRandomValue(GetRandom()); - return randomValue; - } - public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other); + public static bool operator <(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) < 0; + public static bool operator >(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) > 0; + public static bool operator <=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) <= 0; + public static bool operator >=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) >= 0; + + public static bool operator <(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) < 0; + public static bool operator >(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) > 0; + public static bool operator <=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) <= 0; + public static bool operator >=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) >= 0; + + public static bool operator <(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0; + public static bool operator >(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0; + public static bool operator <=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0; + public static bool operator >=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0; + } """; diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs index fbb1ec0..e8f784f 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs @@ -36,6 +36,8 @@ namespace TestNamespace; { public readonly global::System.String Value; + public static global::System.Type InnerValueType => typeof(global::System.String); + [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)] public StringValueObject() { @@ -76,13 +78,22 @@ public override bool Equals(object? obj) public static explicit operator StringValueObject(global::System.String value) => From(value); public static explicit operator global::System.String(StringValueObject value) => value.Value; - public static StringValueObject NewRandomValue() - { - var randomValue = GenerateRandomValue(GetRandom()); - return randomValue; - } - public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other); + public static bool operator <(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) < 0; + public static bool operator >(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) > 0; + public static bool operator <=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) <= 0; + public static bool operator >=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) >= 0; + + public static bool operator <(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) < 0; + public static bool operator >(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) > 0; + public static bool operator <=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) <= 0; + public static bool operator >=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) >= 0; + + public static bool operator <(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0; + public static bool operator >(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0; + public static bool operator <=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0; + public static bool operator >=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0; + } """; diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs index f02c028..402a263 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs @@ -31,6 +31,8 @@ namespace TestNamespace; { public readonly global::System.String Value; + public static global::System.Type InnerValueType => typeof(global::System.String); + [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)] public Int32ValueObject() { @@ -83,6 +85,21 @@ public static Int32ValueObject NewRandomValue() } public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other); + public static bool operator <(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) < 0; + public static bool operator >(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) > 0; + public static bool operator <=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) <= 0; + public static bool operator >=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) >= 0; + + public static bool operator <(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) < 0; + public static bool operator >(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) > 0; + public static bool operator <=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) <= 0; + public static bool operator >=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) >= 0; + + public static bool operator <(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0; + public static bool operator >(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0; + public static bool operator <=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0; + public static bool operator >=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0; + } """; diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs index 152093c..1524130 100644 --- a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs +++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs @@ -34,6 +34,8 @@ namespace TestNamespace; { public readonly global::System.String Value; + public static global::System.Type InnerValueType => typeof(global::System.String); + [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)] public Int32ValueObject() { @@ -85,6 +87,21 @@ public static Int32ValueObject NewRandomValue() } public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other); + public static bool operator <(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) < 0; + public static bool operator >(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) > 0; + public static bool operator <=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) <= 0; + public static bool operator >=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) >= 0; + + public static bool operator <(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) < 0; + public static bool operator >(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) > 0; + public static bool operator <=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) <= 0; + public static bool operator >=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) >= 0; + + public static bool operator <(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0; + public static bool operator >(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0; + public static bool operator <=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0; + public static bool operator >=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0; + } """; From 8d4138b887ed2fcd30814e12487f3329a6ee469b Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 9 Nov 2023 18:48:23 +0200 Subject: [PATCH 10/10] Added docs --- .../IHasRandomValueGenerator.cs | 14 ++++++++++++++ .../IHasUnmanagedRandomValueGenerator.cs | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs index abe92a4..7bc3b95 100644 --- a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs +++ b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs @@ -2,12 +2,26 @@ namespace TransparentValueObjects.Augments; +/// +/// Augment to enable support for random value generation via . +/// +/// +/// +/// public interface IHasRandomValueGenerator where TValueObject : IValueObject where TValue : notnull where TRandom : Random { + /// + /// Gets the random source. can be used for better performance. + /// + /// public static abstract TRandom GetRandom(); + /// + /// Gets the random object. + /// + /// public static abstract TValueObject NewRandomValue(); } diff --git a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs index 923a71c..4ecbd00 100644 --- a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs +++ b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs @@ -2,6 +2,13 @@ namespace TransparentValueObjects.Augments; +/// +/// Augment to extend support for random value generation via . +/// Provides a high performance implementation for structs. +/// +/// +/// +/// public interface IHasUnmanagedRandomValueGenerator : IHasRandomValueGenerator where TValueObject : IValueObject where TValue : unmanaged