Skip to content

Source code generator for enum types

Compare
Choose a tag to compare
@MichalBrylka MichalBrylka released this 01 Jan 22:51
· 10 commits to main since this release
c1aa684

What's Changed

Full Changelog: 2.8.2...2.9.1

Code generator for enum types

With this feature it is enough to annotate enum with 2 attributes:

[Auto.AutoEnumTransformer(
    //1. optionally pass parser settings
    CaseInsensitive = true, AllowParsingNumerics = true, 
    //2. TransformerClassName can be left blank. In that case the name of enum is used with "Transformer" suffix
    TransformerClassName = "MonthCodeGenTransformer",
    //3. optionally pass namespace to generate the transformer class within. If not provided the namespace of the enum will be used
    TransformerClassNamespace = "ABC"
)]
//4. decorate enum with TransformerAttribute that points to automatically generated transformer
[Transformer(typeof(ABC.MonthCodeGenTransformer))]
public enum Month : byte
{
    None = 0,
    January = 1, February = 2, March = 3,
    April = 4, May = 5, June = 6,
    July = 7, August = 8, September = 9,
    October = 10, November = 11, December = 12
}

This in turn generates the following parser using best practices (some lines are ommited for brevity):

Source code for generated parser
public sealed class MonthCodeGenTransformer : TransformerBase<Nemesis.TextParsers.CodeGen.Sample.Month>
{
    public override string Format(Nemesis.TextParsers.CodeGen.Sample.Month element) => element switch
    {
        Nemesis.TextParsers.CodeGen.Sample.Month.None => nameof(Nemesis.TextParsers.CodeGen.Sample.Month.None),
        Nemesis.TextParsers.CodeGen.Sample.Month.January => nameof(Nemesis.TextParsers.CodeGen.Sample.Month.January),
        
        // ...

        Nemesis.TextParsers.CodeGen.Sample.Month.December => nameof(Nemesis.TextParsers.CodeGen.Sample.Month.December),
        _ => element.ToString("G"),
    };

    protected override Nemesis.TextParsers.CodeGen.Sample.Month ParseCore(in ReadOnlySpan<char> input) =>
        input.IsWhiteSpace() ? default : (Nemesis.TextParsers.CodeGen.Sample.Month)ParseElement(input);

    private static byte ParseElement(ReadOnlySpan<char> input)
    {
        if (input.IsEmpty || input.IsWhiteSpace()) return default;
        input = input.Trim();
        if (IsNumeric(input) && byte.TryParse(input
#if NETFRAMEWORK
    .ToString() //legacy frameworks do not support parsing from ReadOnlySpan<char>
#endif
            , out var number))
            return number;
        else
            return ParseName(input);


        static bool IsNumeric(ReadOnlySpan<char> input) =>
            input.Length > 0 && input[0] is var first &&
            (char.IsDigit(first) || first is '-' or '+');    
    }

    private static byte ParseName(ReadOnlySpan<char> input)
    {    
        if (IsEqual(input, nameof(Nemesis.TextParsers.CodeGen.Sample.Month.None)))
            return (byte)Nemesis.TextParsers.CodeGen.Sample.Month.None;            

        else if (IsEqual(input, nameof(Nemesis.TextParsers.CodeGen.Sample.Month.January)))
            return (byte)Nemesis.TextParsers.CodeGen.Sample.Month.January;            

        else if (IsEqual(input, nameof(Nemesis.TextParsers.CodeGen.Sample.Month.February)))
            return (byte)Nemesis.TextParsers.CodeGen.Sample.Month.February;            

        // ...         

        else if (IsEqual(input, nameof(Nemesis.TextParsers.CodeGen.Sample.Month.December)))
            return (byte)Nemesis.TextParsers.CodeGen.Sample.Month.December;            

        else throw new FormatException(@$"Enum of type 'Nemesis.TextParsers.CodeGen.Sample.Month' cannot be parsed from '{input.ToString()}'.
Valid values are: [None or January or February or March or April or May or June or July or August or September or October or November or December] or number within byte range. 
Ignore case option on.");        

        static bool IsEqual(ReadOnlySpan<char> input, string label) =>
            MemoryExtensions.Equals(input, label.AsSpan(), StringComparison.OrdinalIgnoreCase);
    }
}