diff --git a/Supernova.Enum.Generators/EnumSourceGenerator.cs b/Supernova.Enum.Generators/EnumSourceGenerator.cs index 7ab0f1a..69fa5e7 100644 --- a/Supernova.Enum.Generators/EnumSourceGenerator.cs +++ b/Supernova.Enum.Generators/EnumSourceGenerator.cs @@ -80,6 +80,8 @@ public sealed class {SourceGeneratorHelper.AttributeName}Attribute : Attribute /**********************/ var enumDisplayNames = new Dictionary(StringComparer.OrdinalIgnoreCase); var enumDescriptions = new Dictionary(StringComparer.OrdinalIgnoreCase); + var enumShortNames = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var member in enumSymbol.GetMembers()) { if (member is not IFieldSymbol field @@ -103,7 +105,11 @@ public sealed class {SourceGeneratorHelper.AttributeName}Attribute : Attribute { enumDescriptions.Add(member.Name, description); } - + if (namedArgument.Key.Equals("ShortName", StringComparison.OrdinalIgnoreCase) && + namedArgument.Value.Value?.ToString() is { } shortName) + { + enumShortNames.Add(member.Name, shortName); + } } } } @@ -126,6 +132,9 @@ namespace {SourceGeneratorHelper.NameSpace} //DisplayNames Dictionary DisplayNamesDictionary(sourceBuilder, symbol, e, enumDisplayNames); + //DisplayShortNames Dictionary + DisplayShortNamesDictionary(sourceBuilder, symbol, e, enumShortNames); + //DisplayDescriptions Dictionary DisplayDescriptionsDictionary(sourceBuilder, symbol, e, enumDescriptions); @@ -144,6 +153,9 @@ namespace {SourceGeneratorHelper.NameSpace} //ToDisplay string ToDescription(sourceBuilder, symbol, e, enumDescriptions); + //ToShortName + ToShortName(sourceBuilder, symbol, e, enumShortNames); + //GetValues GetValuesFast(sourceBuilder, symbol, e); @@ -199,6 +211,37 @@ private static void ToDisplay(StringBuilder sourceBuilder, ISymbol symbol, EnumD "); } + private static void ToShortName(StringBuilder sourceBuilder, ISymbol symbol, EnumDeclarationSyntax e, Dictionary enumShortNames) + { + sourceBuilder.Append($@" + /// + /// Converts the enumeration value to its short name string. + /// + /// The enumeration value. + /// The default value to return if the enumeration value is not recognized. + /// The short name string of the value. + public static string {SourceGeneratorHelper.ExtensionMethodNameToShortName}(this {symbol.FullName()} states, string defaultValue = null) + {{ + return states switch + {{ +"); + foreach (var member in e.Members) + { + var key = member.Identifier.ValueText; + var enumShortName = enumShortNames.TryGetValue(key, out var found) + ? found + : key; + sourceBuilder.AppendLine( + $@" {symbol}.{member.Identifier.ValueText} => ""{enumShortName}"","); + } + + sourceBuilder.Append( + @" _ => defaultValue ?? throw new ArgumentOutOfRangeException(nameof(states), states, null) + }; + } +"); + } + private static void ToDescription(StringBuilder sourceBuilder, ISymbol symbol, EnumDeclarationSyntax e, Dictionary enumDescriptions) { @@ -348,6 +391,31 @@ private static void DisplayDescriptionsDictionary(StringBuilder sourceBuilder, I "); } + private static void DisplayShortNamesDictionary(StringBuilder sourceBuilder, ISymbol symbol, EnumDeclarationSyntax e, + Dictionary enumShortNames) + { + sourceBuilder.Append($@" + /// + /// Provides a dictionary that maps values to their corresponding short names. + /// + public static readonly ImmutableDictionary<{symbol.FullName()}, string> {SourceGeneratorHelper.PropertyDisplayShortNamesDictionary} = new Dictionary<{symbol.FullName()}, string> + {{ +"); + foreach (var member in e.Members) + { + var key = member.Identifier.ValueText; + var enumShortName = enumShortNames.TryGetValue(key, out var found) + ? found + : key; + sourceBuilder.AppendLine( + $@" {{{symbol}.{member.Identifier.ValueText}, ""{enumShortName}""}},"); + } + sourceBuilder.Append( + @" + }.ToImmutableDictionary(); +"); + } + private static void GetValuesFast(StringBuilder sourceBuilder, ISymbol symbol, EnumDeclarationSyntax e) { sourceBuilder.Append($@" diff --git a/Supernova.Enum.Generators/SourceGeneratorHelper.cs b/Supernova.Enum.Generators/SourceGeneratorHelper.cs index 4823c15..09b7837 100644 --- a/Supernova.Enum.Generators/SourceGeneratorHelper.cs +++ b/Supernova.Enum.Generators/SourceGeneratorHelper.cs @@ -8,11 +8,13 @@ public static class SourceGeneratorHelper public const string ExtensionMethodNameIsDefined = "IsDefinedFast"; public const string ExtensionMethodNameToDisplay = "ToDisplayFast"; public const string ExtensionMethodNameToDescription = "ToDescriptionFast"; + public const string ExtensionMethodNameToShortName = "ToShortNameFast"; public const string ExtensionMethodNameGetValues = "GetValuesFast"; public const string ExtensionMethodNameGetNames = "GetNamesFast"; public const string ExtensionMethodNameGetLength = "GetLengthFast"; public const string ExtensionMethodNameTryParse = "TryParseFast"; public const string PropertyDisplayNamesDictionary = "DisplayNamesDictionary"; + public const string PropertyDisplayShortNamesDictionary = "DisplayShortNamesDictionary"; public const string PropertyDisplayDescriptionsDictionary = "DisplayDescriptionsDictionary"; } diff --git a/test/Console.Test.Benchmark/Program.cs b/test/Console.Test.Benchmark/Program.cs index da49a6f..8abcff2 100644 --- a/test/Console.Test.Benchmark/Program.cs +++ b/test/Console.Test.Benchmark/Program.cs @@ -21,9 +21,9 @@ namespace Console.Test.Benchmark; [EnumGenerator] public enum UserType { - [Display(Name = "مرد", Description = "men")] Men, + [Display(Name = "مرد", Description = "men", ShortName = "M")] Men, - [Display(Name = "زن", Description = "women")] Women, + [Display(Name = "زن", Description = "women", ShortName = "W")] Women, //[Display(Name = "نامشخص")] None @@ -97,6 +97,18 @@ public string FastToDisplay() return UserType.Men.ToDisplayFast(); } + [Benchmark] + public string NativeToShortName() + { + return UserType.Men.ToShortNameNative(); + } + + [Benchmark] + public string FastToShortName() + { + return UserType.Men.ToShortNameFast(); + } + [Benchmark] public string NativeToDescription() { @@ -173,6 +185,19 @@ public static string ToDisplayNative(this Enum value) return propValue?.ToString(); } + + public static string ToShortNameNative(this Enum value) + { + if (value is null) + throw new ArgumentNullException(nameof(value)); + var attribute = value.GetType().GetField(value.ToString())? + .GetCustomAttributes(false).FirstOrDefault(); + if (attribute == null) + return value.ToString(); + var propValue = attribute.GetType().GetProperty(ShortNameProperty)?.GetValue(attribute, null); + return propValue?.ToString(); + } + public static string ToDescriptionNative(this Enum value) { if (value is null) diff --git a/test/UnitTests/EnumGeneratorTest.cs b/test/UnitTests/EnumGeneratorTest.cs index 8b2dc84..42db06e 100644 --- a/test/UnitTests/EnumGeneratorTest.cs +++ b/test/UnitTests/EnumGeneratorTest.cs @@ -10,9 +10,9 @@ namespace UnitTests; [EnumGenerator] public enum UserTypeTest { - [Display(Name = "مرد", Description = "Descمرد")] Men = 3, + [Display(Name = "مرد", Description = "Descمرد", ShortName = "M")] Men = 3, - [Display(Name = "زن", Description = "Descزن")] Women = 4, + [Display(Name = "زن", Description = "Descزن", ShortName = "W")] Women = 4, //[Display(Name = "نامشخص")] None @@ -117,6 +117,32 @@ public void TestEnumToDisplay_Undefined_DefaultValue() value.Should().Be("DefaultValue"); } + [TestMethod] + public void TestEnumToShortName() + { + var menShortName = UserTypeTest.Men.ToShortNameFast(); + var womenShortName = UserTypeTest.Women.ToShortNameFast(); + var noneShortName = UserTypeTest.None.ToShortNameFast(); + + menShortName.Should().Be("M"); + womenShortName.Should().Be("W"); + noneShortName.Should().Be("None"); + } + + [TestMethod] + public void TestEnumToShortName_Undefined() + { + var action = () => GetUndefinedEnumValue().ToShortNameFast(); + action.Should().Throw(); + } + + [TestMethod] + public void TestEnumToShortName_Undefined_DefaultValue() + { + var value = GetUndefinedEnumValue().ToShortNameFast("DefaultValue"); + value.Should().Be("DefaultValue"); + } + [TestMethod] public void TestEnumGetNames() { @@ -142,6 +168,20 @@ public void TestEnumDisplayNamesDictionary() new KeyValuePair(UserTypeTest.None, "None") ); } + + [TestMethod] + public void TestEnumDisplayShortNamesDictionary() + { + var names = UserTypeTestEnumExtensions.DisplayShortNamesDictionary; + Assert.IsNotNull(names); + names.Should().NotBeEmpty() + .And.HaveCount(3) + .And.ContainInOrder( + new KeyValuePair(UserTypeTest.Men, "M"), + new KeyValuePair(UserTypeTest.Women, "W"), + new KeyValuePair(UserTypeTest.None, "None") + ); + } [TestMethod] public void TestEnumDisplayDescriptionsDictionary() diff --git a/test/UnitTests/InternalEnumGeneratorTest.cs b/test/UnitTests/InternalEnumGeneratorTest.cs index 84a5a5a..e48e4e0 100644 --- a/test/UnitTests/InternalEnumGeneratorTest.cs +++ b/test/UnitTests/InternalEnumGeneratorTest.cs @@ -10,9 +10,9 @@ namespace UnitTests; [EnumGenerator] internal enum InternalUserTypeTest { - [Display(Name = "مرد", Description = "Descمرد")] Men = 3, + [Display(Name = "مرد", Description = "Descمرد", ShortName = "M")] Men = 3, - [Display(Name = "زن", Description = "Descزن")] Women = 4, + [Display(Name = "زن", Description = "Descزن", ShortName = "W")] Women = 4, //[Display(Name = "نامشخص")] None @@ -117,6 +117,32 @@ public void TestEnumToDisplay_Undefined_DefaultValue() value.Should().Be("DefaultValue"); } + [TestMethod] + public void TestEnumToShortName() + { + var menShortName = InternalUserTypeTest.Men.ToShortNameFast(); + var womenShortName = InternalUserTypeTest.Women.ToShortNameFast(); + var noneShortName = InternalUserTypeTest.None.ToShortNameFast(); + + menShortName.Should().Be("M"); + womenShortName.Should().Be("W"); + noneShortName.Should().Be("None"); + } + + [TestMethod] + public void TestEnumToShortName_Undefined() + { + var action = () => GetUndefinedEnumValue().ToShortNameFast(); + action.Should().Throw(); + } + + [TestMethod] + public void TestEnumToShortName_Undefined_DefaultValue() + { + var value = GetUndefinedEnumValue().ToShortNameFast("DefaultValue"); + value.Should().Be("DefaultValue"); + } + [TestMethod] public void TestEnumGetNames() { @@ -142,6 +168,20 @@ public void TestEnumDisplayNamesDictionary() new KeyValuePair(InternalUserTypeTest.None, "None") ); } + + [TestMethod] + public void TestEnumDisplayShortNamesDictionary() + { + var names = InternalUserTypeTestEnumExtensions.DisplayShortNamesDictionary; + Assert.IsNotNull(names); + names.Should().NotBeEmpty() + .And.HaveCount(3) + .And.ContainInOrder( + new KeyValuePair(InternalUserTypeTest.Men, "M"), + new KeyValuePair(InternalUserTypeTest.Women, "W"), + new KeyValuePair(InternalUserTypeTest.None, "None") + ); + } [TestMethod] public void TestEnumDisplayDescriptionsDictionary()