diff --git a/README.md b/README.md index d06760e..0dab20d 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,25 @@ public readonly partial struct Hp { } // -- generates [System.ComponentModel.TypeConverter(typeof(HpTypeConverter))] -public readonly partial struct Hp : IEquatable , IComparable +public readonly partial struct Hp + : IEquatable +#if NET7_0_OR_GREATER + , IEqualityOperators +#endif + , IComparable +#if NET7_0_OR_GREATER + , IComparisonOperators +#endif +#if NET7_0_OR_GREATER + , IAdditionOperators + , ISubtractionOperators + , IMultiplyOperators + , IDivisionOperators + , IUnaryPlusOperators + , IUnaryNegationOperators + , IIncrementOperators + , IDecrementOperators +#endif { readonly int value; @@ -81,25 +99,27 @@ public readonly partial struct Hp : IEquatable , IComparable private class HpTypeConverter : System.ComponentModel.TypeConverter { /* snip... */ } // UnitGenerateOptions.ArithmeticOperator - public static Hp operator +(in Hp x, in Hp y) => new Hp(checked((int)(x.value + y.value))); - public static Hp operator -(in Hp x, in Hp y) => new Hp(checked((int)(x.value - y.value))); - public static Hp operator *(in Hp x, in Hp y) => new Hp(checked((int)(x.value * y.value))); - public static Hp operator /(in Hp x, in Hp y) => new Hp(checked((int)(x.value / y.value))); + public static Hp operator +(Hp x, Hp y) => new Hp(checked((int)(x.value + y.value))); + public static Hp operator -(Hp x, Hp y) => new Hp(checked((int)(x.value - y.value))); + public static Hp operator *(Hp x, Hp y) => new Hp(checked((int)(x.value * y.value))); + public static Hp operator /(Hp x, Hp y) => new Hp(checked((int)(x.value / y.value))); + public static Hp operator ++(Hp x) => new Hp(checked((int)(x.value + 1))); + public static Hp operator --(Hp x) => new Hp(checked((int)(x.value - 1))); + public static Hp operator +(A value) => new((int)(+value.value)); + public static Hp operator -(A value) => new((int)(-value.value)); // UnitGenerateOptions.ValueArithmeticOperator - public static Hp operator ++(in Hp x) => new Hp(checked((int)(x.value + 1))); - public static Hp operator --(in Hp x) => new Hp(checked((int)(x.value - 1))); - public static Hp operator +(in Hp x, in int y) => new Hp(checked((int)(x.value + y))); - public static Hp operator -(in Hp x, in int y) => new Hp(checked((int)(x.value - y))); - public static Hp operator *(in Hp x, in int y) => new Hp(checked((int)(x.value * y))); - public static Hp operator /(in Hp x, in int y) => new Hp(checked((int)(x.value / y))); + public static Hp operator +(Hp x, in int y) => new Hp(checked((int)(x.value + y))); + public static Hp operator -(Hp x, in int y) => new Hp(checked((int)(x.value - y))); + public static Hp operator *(Hp x, in int y) => new Hp(checked((int)(x.value * y))); + public static Hp operator /(Hp x, in int y) => new Hp(checked((int)(x.value / y))); // UnitGenerateOptions.Comparable public int CompareTo(Hp other) => value.CompareTo(other.value); - public static bool operator >(in Hp x, in Hp y) => x.value > y.value; - public static bool operator <(in Hp x, in Hp y) => x.value < y.value; - public static bool operator >=(in Hp x, in Hp y) => x.value >= y.value; - public static bool operator <=(in Hp x, in Hp y) => x.value <= y.value; + public static bool operator >(Hp x, Hp y) => x.value > y.value; + public static bool operator <(Hp x, Hp y) => x.value < y.value; + public static bool operator >=(Hp x, Hp y) => x.value >= y.value; + public static bool operator <=(Hp x, Hp y) => x.value <= y.value; // UnitGenerateOptions.MinMaxMethod public static Hp Min(Hp x, Hp y) => new Hp(Math.Min(x.value, y.value)); @@ -193,7 +213,12 @@ namespace UnitGenerator [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)] internal class UnitOfAttribute : Attribute { - public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None, string toStringFormat = null) + public Type Type { get; } + public UnitGenerateOptions Options { get; } + public UnitArithmeticOperators ArithmeticOperators { get; set; } + public string ToStringFormat { get; set; } + + public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None) { ... } } } ``` @@ -241,7 +266,9 @@ public static GroupId NewGroupId(); Second parameter `UnitGenerateOptions options` can configure which method to implement, default is `None`. -Third parameter `strign toStringFormat` can configure `ToString` format. Default is null and output as $`{0}`. +Optional named parameter: `ArithmeticOperators` can configure which generates operators specifically. Default is `Number`. (This can be used if UnitGenerateOptions.ArithmeticOperator is specified.) + +Optional named parameter: `ToStringFormat` can configure `ToString` format. Default is null and output as $`{0}`. ## UnitGenerateOptions @@ -324,13 +351,36 @@ public static T operator +(in T x, in T y) => new T(checked((U)(x.value + y.valu public static T operator -(in T x, in T y) => new T(checked((U)(x.value - y.value))); public static T operator *(in T x, in T y) => new T(checked((U)(x.value * y.value))); public static T operator /(in T x, in T y) => new T(checked((U)(x.value / y.value))); +public static T operator +(T value) => new((U)(+value.value)); +public static T operator -(T value) => new((U)(-value.value)); +public static T operator ++(T x) => new T(checked((U)(x.value + 1))); +public static T operator --(T x) => new T(checked((U)(x.value - 1))); +``` + +In addition, all members conforming to [System.Numerics.INumber](https://learn.microsoft.com/ja-jp/dotnet/api/system.numerics.inumber-1) are generated. + +If you want to suppress this and generate only certain operators, you can use the the `ArithmeticOperatros` option of `[UnitOf]` attribute as follows: + +```csharp +[UnitOf( + typeof(int), + UnitGenerateOptions.ArithmeticOperator, + ArithmeticOperators = UnitArithmeticOperators.Addition | UnitArithmeticOperators.Subtraction)] +public readonly partial struct Hp { } ``` +| Value | Generates | +|-------------------------------------|----------------------------------------------------------------------------------------| +| UnitArithmeticOperators.Addition | `T operator +(T, T)` | +| UnitArithmeticOperators.Subtraction | `T operator -(T, T)` | +| UnitArithmeticOperators.Multiply | `T operator *(T, T)`, `T operator +(T)`, `T operator-(T)` | +| UnitArithmeticOperators.Division | `T operator /(T, T)`, `T operator +(T)`, `T operator-(T)` | +| UnitArithmeticOperators.Increment | `T operator ++(T)` | +| UnitArithmeticOperators.Decrement | `T operator --(T)` | + ### ValueArithmeticOperator ```csharp -public static T operator ++(in T x) => new T(checked((U)(x.value + 1))); -public static T operator --(in T x) => new T(checked((U)(x.value - 1))); public static T operator +(in T x, in U y) => new T(checked((U)(x.value + y))); public static T operator -(in T x, in U y) => new T(checked((U)(x.value - y))); public static T operator *(in T x, in U y) => new T(checked((U)(x.value * y))); diff --git a/sandbox/ConsoleApp/AllPrimitives.cs b/sandbox/ConsoleApp/AllPrimitives.cs index 7433c77..b16deb6 100644 --- a/sandbox/ConsoleApp/AllPrimitives.cs +++ b/sandbox/ConsoleApp/AllPrimitives.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Numerics; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/sandbox/ConsoleApp/ConsoleApp.csproj b/sandbox/ConsoleApp/ConsoleApp.csproj index 9035ba9..cc776ea 100644 --- a/sandbox/ConsoleApp/ConsoleApp.csproj +++ b/sandbox/ConsoleApp/ConsoleApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0 enable false diff --git a/sandbox/ConsoleApp/Operators.cs b/sandbox/ConsoleApp/Operators.cs new file mode 100644 index 0000000..ff31ef6 --- /dev/null +++ b/sandbox/ConsoleApp/Operators.cs @@ -0,0 +1,37 @@ +using UnitGenerator; + +namespace ConsoleApp +{ + namespace ConsoleApp + { + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Addition)] + public readonly partial struct Add + { + } + + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Subtraction)] + public readonly partial struct Sub + { + } + + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Multiply)] + public readonly partial struct Mul + { + } + + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Division)] + public readonly partial struct Div + { + } + + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Increment)] + public readonly partial struct Inc + { + } + + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator, ArithmeticOperators = UnitArithmeticOperators.Decrement)] + public readonly partial struct Dec + { + } + } +} diff --git a/sandbox/ConsoleApp/Program.cs b/sandbox/ConsoleApp/Program.cs index 84f0262..5b291fe 100644 --- a/sandbox/ConsoleApp/Program.cs +++ b/sandbox/ConsoleApp/Program.cs @@ -35,8 +35,7 @@ public readonly partial struct BarId { } namespace Sample { - - [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator | UnitGenerateOptions.Comparable | UnitGenerateOptions.MinMaxMethod | UnitGenerateOptions.JsonConverter | UnitGenerateOptions.JsonConverterDictionaryKeySupport)] + [UnitOf(typeof(int), UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.Comparable | UnitGenerateOptions.MinMaxMethod | UnitGenerateOptions.JsonConverter | UnitGenerateOptions.JsonConverterDictionaryKeySupport)] public readonly partial struct Hp { // public static Hp operator +(in Hp x, in Hp y) => new Hp(checked((int)(x.value + y.value))); @@ -83,7 +82,7 @@ public void Foo() _ = AsPrimitive(); } } - + [UnitOf(typeof(string), UnitGenerateOptions.ParseMethod)] public readonly partial struct StringId { } } diff --git a/sandbox/FileGenerate/FileGenerate.csproj b/sandbox/FileGenerate/FileGenerate.csproj index 96575cf..3373f19 100644 --- a/sandbox/FileGenerate/FileGenerate.csproj +++ b/sandbox/FileGenerate/FileGenerate.csproj @@ -1,7 +1,7 @@  - net6.0 + net7.0 true $(ProjectDir)..\Generated diff --git a/sandbox/FileGenerate/SimplePrimitive.cs b/sandbox/FileGenerate/SimplePrimitive.cs index 6e521fa..705e25c 100644 --- a/sandbox/FileGenerate/SimplePrimitive.cs +++ b/sandbox/FileGenerate/SimplePrimitive.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnitGenerator; +using UnitGenerator; namespace FileGenerate { @@ -16,4 +11,9 @@ public readonly partial struct A public readonly partial struct B { } + + [UnitOf(typeof(int), UnitGenerateOptions.Comparable | UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator)] + public readonly partial struct C + { + } } diff --git a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.A.Generated.cs b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.A.Generated.cs index 6608197..4074261 100644 --- a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.A.Generated.cs +++ b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.A.Generated.cs @@ -3,10 +3,18 @@ // #pragma warning disable CS8669 using System; +using System.Globalization; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif namespace FileGenerate { [System.ComponentModel.TypeConverter(typeof(ATypeConverter))] - readonly partial struct A : IEquatable + readonly partial struct A + : IEquatable +#if NET7_0_OR_GREATER + , IEqualityOperators +#endif { readonly int value; @@ -47,28 +55,29 @@ public override bool Equals(object obj) return value.Equals(obj); } - - public override int GetHashCode() + + public static bool operator ==(A x, A y) { - return value.GetHashCode(); + return x.value.Equals(y.value); } - public override string ToString() + public static bool operator !=(A x, A y) { - return value.ToString(); + return !x.value.Equals(y.value); } - public static bool operator ==(in A x, in A y) + public override int GetHashCode() { - return x.value.Equals(y.value); + return value.GetHashCode(); } - public static bool operator !=(in A x, in A y) + public override string ToString() { - return !x.value.Equals(y.value); + return value.ToString(); } // Default + private class ATypeConverter : System.ComponentModel.TypeConverter { private static readonly Type WrapperType = typeof(A); diff --git a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.B.Generated.cs b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.B.Generated.cs index 6173d2b..75fc7bf 100644 --- a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.B.Generated.cs +++ b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.B.Generated.cs @@ -3,10 +3,18 @@ // #pragma warning disable CS8669 using System; +using System.Globalization; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif namespace FileGenerate { [System.ComponentModel.TypeConverter(typeof(BTypeConverter))] - readonly partial struct B : IEquatable + readonly partial struct B + : IEquatable +#if NET7_0_OR_GREATER + , IEqualityOperators +#endif { readonly string value; @@ -47,28 +55,29 @@ public override bool Equals(object obj) return value.Equals(obj); } - - public override int GetHashCode() + + public static bool operator ==(B x, B y) { - return value.GetHashCode(); + return x.value.Equals(y.value); } - public override string ToString() + public static bool operator !=(B x, B y) { - return value.ToString(); + return !x.value.Equals(y.value); } - public static bool operator ==(in B x, in B y) + public override int GetHashCode() { - return x.value.Equals(y.value); + return value.GetHashCode(); } - public static bool operator !=(in B x, in B y) + public override string ToString() { - return !x.value.Equals(y.value); + return value.ToString(); } // Default + private class BTypeConverter : System.ComponentModel.TypeConverter { private static readonly Type WrapperType = typeof(B); diff --git a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.C.Generated.cs b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.C.Generated.cs new file mode 100644 index 0000000..09fe8e8 --- /dev/null +++ b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.C.Generated.cs @@ -0,0 +1,272 @@ +// +// THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT. +// +#pragma warning disable CS8669 +using System; +using System.Globalization; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif +namespace FileGenerate +{ + [System.ComponentModel.TypeConverter(typeof(CTypeConverter))] + readonly partial struct C + : IEquatable +#if NET7_0_OR_GREATER + , IEqualityOperators +#endif + , IComparable +#if NET7_0_OR_GREATER + , IComparisonOperators +#endif +#if NET7_0_OR_GREATER + , IAdditionOperators + , ISubtractionOperators + , IMultiplyOperators + , IDivisionOperators + , IUnaryPlusOperators + , IUnaryNegationOperators + , IIncrementOperators + , IDecrementOperators +#endif + { + readonly int value; + + public int AsPrimitive() => value; + + public C(int value) + { + this.value = value; + } + + public static explicit operator int(C value) + { + return value.value; + } + + public static explicit operator C(int value) + { + return new C(value); + } + + public bool Equals(C other) + { + return value.Equals(other.value); + } + + public override bool Equals(object obj) + { + if (obj == null) return false; + var t = obj.GetType(); + if (t == typeof(C)) + { + return Equals((C)obj); + } + if (t == typeof(int)) + { + return value.Equals((int)obj); + } + + return value.Equals(obj); + } + + public static bool operator ==(C x, C y) + { + return x.value.Equals(y.value); + } + + public static bool operator !=(C x, C y) + { + return !x.value.Equals(y.value); + } + + public override int GetHashCode() + { + return value.GetHashCode(); + } + + public override string ToString() + { + return value.ToString(); + } + + // UnitGenerateOptions.ArithmeticOperator + + public static C operator +(C x, C y) + { + checked + { + return new C((int)(x.value + y.value)); + } + } + + public static C operator -(C x, C y) + { + checked + { + return new C((int)(x.value - y.value)); + } + } + + public static C operator +(C value) => new((int)(+value.value)); + public static C operator -(C value) => new((int)(-value.value)); + + public static C operator *(C x, C y) + { + checked + { + return new C((int)(x.value * y.value)); + } + } + + + public static C operator /(C x, C y) + { + checked + { + return new C((int)(x.value / y.value)); + } + } + + public static C operator ++(C x) + { + checked + { + return new C((int)((int)(x.value + 1))); + } + } + + public static C operator --(C x) + { + checked + { + return new C((int)((int)(x.value - 1))); + } + } + + // UnitGenerateOptions.ValueArithmeticOperator + + public static C operator +(C x, int y) + { + checked + { + return new C((int)(x.value + y)); + } + } + + public static C operator -(C x, int y) + { + checked + { + return new C((int)(x.value - y)); + } + } + + public static C operator *(C x, int y) + { + checked + { + return new C((int)(x.value * y)); + } + } + + + public static C operator /(C x, int y) + { + checked + { + return new C((int)(x.value / y)); + } + } + + // UnitGenerateOptions.Comparable + + public int CompareTo(C other) + { + return value.CompareTo(other.value); + } + public static bool operator >(C x, C y) + { + return x.value > y.value; + } + + public static bool operator <(C x, C y) + { + return x.value < y.value; + } + + public static bool operator >=(C x, C y) + { + return x.value >= y.value; + } + + public static bool operator <=(C x, C y) + { + return x.value <= y.value; + } + + // Default + + private class CTypeConverter : System.ComponentModel.TypeConverter + { + private static readonly Type WrapperType = typeof(C); + private static readonly Type ValueType = typeof(int); + + public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == WrapperType || sourceType == ValueType) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == WrapperType || destinationType == ValueType) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if (value != null) + { + var t = value.GetType(); + if (t == typeof(C)) + { + return (C)value; + } + if (t == typeof(int)) + { + return new C((int)value); + } + } + + return base.ConvertFrom(context, culture, value); + } + + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (value is C wrappedValue) + { + if (destinationType == WrapperType) + { + return wrappedValue; + } + + if (destinationType == ValueType) + { + return wrappedValue.AsPrimitive(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + } +} diff --git a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/UnitOfAttribute.cs b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/UnitOfAttribute.cs index 6eb676e..de69d92 100644 --- a/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/UnitOfAttribute.cs +++ b/sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/UnitOfAttribute.cs @@ -4,6 +4,9 @@ #pragma warning disable CS8669 #pragma warning disable CS8625 using System; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif namespace UnitGenerator { @@ -12,16 +15,16 @@ internal class UnitOfAttribute : Attribute { public Type Type { get; } public UnitGenerateOptions Options { get; } - public string Format { get; } + public UnitArithmeticOperators ArithmeticOperators { get; set; } = UnitArithmeticOperators.All; + public string ToStringFormat { get; set; } - public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None, string toStringFormat = null) + public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None) { this.Type = type; this.Options = options; - this.Format = toStringFormat; } } - + [Flags] internal enum UnitGenerateOptions { @@ -41,4 +44,16 @@ internal enum UnitGenerateOptions JsonConverterDictionaryKeySupport = 1 << 12, Normalize = 1 << 13, } -} \ No newline at end of file + + [Flags] + internal enum UnitArithmeticOperators + { + All = Addition | Subtraction | Multiply | Division | Increment | Decrement, + Addition = 1, + Subtraction = 1 << 1, + Multiply = 1 << 2, + Division = 1 << 3, + Increment = 1 << 4, + Decrement = 1 << 5, + } +} diff --git a/src/EntityFrameworkApp/EntityFrameworkApp.csproj b/src/EntityFrameworkApp/EntityFrameworkApp.csproj index e68d3c8..a57606c 100644 --- a/src/EntityFrameworkApp/EntityFrameworkApp.csproj +++ b/src/EntityFrameworkApp/EntityFrameworkApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0 enable enable diff --git a/src/UnitGenerator/SourceGenerator.cs b/src/UnitGenerator/SourceGenerator.cs index 88a1b06..1a4d7fd 100644 --- a/src/UnitGenerator/SourceGenerator.cs +++ b/src/UnitGenerator/SourceGenerator.cs @@ -33,9 +33,10 @@ public void Execute(GeneratorExecutionContext context) var model = context.Compilation.GetSemanticModel(type.SyntaxTree); // retrieve attribute parameter - var prop = new UnitOfAttributeProperty(); + var prop = new UnitOfAttributeProperty { ArithmeticOperators = UnitArithmeticOperators.All }; if (attr.ArgumentList is null) goto ADD; + for (int i = 0; i < attr.ArgumentList.Arguments.Count; i++) { var arg = attr.ArgumentList.Arguments[i]; @@ -60,10 +61,20 @@ public void Execute(GeneratorExecutionContext context) var parsed = Enum.ToObject(typeof(UnitGenerateOptions), model.GetConstantValue(expr).Value); prop.Options = (UnitGenerateOptions)parsed; } - else if (i == 2) // string toStringFormat + else { - var format = model.GetConstantValue(expr).Value?.ToString(); - prop.ToStringFormat = format; + var argName = arg.NameEquals?.Name.ToString(); + switch (argName) + { + case "ArithmeticOperators": + var parsed = Enum.ToObject(typeof(UnitArithmeticOperators), model.GetConstantValue(expr).Value); + prop.ArithmeticOperators = (UnitArithmeticOperators)parsed; + break; + case "ToStringFormat": + var format = model.GetConstantValue(expr).Value?.ToString(); + prop.ToStringFormat = format; + break; + } } } @@ -85,7 +96,7 @@ public void Execute(GeneratorExecutionContext context) ToStringFormat = prop.ToStringFormat }; - var text = GenerateType(typeSymbol, prop); + var text = GenerateType(typeSymbol, prop); if (template.Namespace == null) { context.AddSource($"{template.Name}.Generated.cs", text); @@ -111,6 +122,9 @@ private void SetDefaultAttribute(GeneratorPostInitializationContext context) #pragma warning disable CS8669 #pragma warning disable CS8625 using System; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif namespace UnitGenerator { @@ -119,16 +133,16 @@ internal class UnitOfAttribute : Attribute { public Type Type { get; } public UnitGenerateOptions Options { get; } - public string Format { get; } + public UnitArithmeticOperators ArithmeticOperators { get; set; } = UnitArithmeticOperators.All; + public string ToStringFormat { get; set; } - public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None, string toStringFormat = null) + public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None) { this.Type = type; this.Options = options; - this.Format = toStringFormat; } } - + [Flags] internal enum UnitGenerateOptions { @@ -148,7 +162,20 @@ internal enum UnitGenerateOptions JsonConverterDictionaryKeySupport = 1 << 12, Normalize = 1 << 13, } + + [Flags] + internal enum UnitArithmeticOperators + { + All = Addition | Subtraction | Multiply | Division | Increment | Decrement, + Addition = 1, + Subtraction = 1 << 1, + Multiply = 1 << 2, + Division = 1 << 3, + Increment = 1 << 4, + Decrement = 1 << 5, + } } + """; context.AddSource("UnitOfAttribute.cs", attrCode); } @@ -158,13 +185,17 @@ private string GenerateType(INamedTypeSymbol symbol, UnitOfAttributeProperty pro var unitTypeName = symbol.Name; var innerTypeName = prop.TypeName; var ns = symbol.ContainingNamespace.IsGlobalNamespace ? null : symbol.ContainingNamespace.ToDisplayString(); - + var sb = new StringBuilder(""" // // THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT. // #pragma warning disable CS8669 using System; +using System.Globalization; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif """); if (prop.HasFlag(UnitGenerateOptions.MessagePackFormatter)) @@ -203,13 +234,79 @@ namespace {{ns}} if (prop.HasFlag(UnitGenerateOptions.MessagePackFormatter)) { sb.AppendLine($$""" - [MessagePackFormatter(typeof({{unitTypeName}}MessagePackFormatter))] + [MessagePackFormatter(typeof({{unitTypeName}}MessagePackFormatter))] """); } - var comparableDeclare = prop.HasFlag(UnitGenerateOptions.Comparable) ? $", IComparable<{unitTypeName}>" : ""; + sb.AppendLine($$""" [System.ComponentModel.TypeConverter(typeof({{unitTypeName}}TypeConverter))] - readonly partial struct {{unitTypeName}} : IEquatable<{{unitTypeName}}>{{comparableDeclare}} + readonly partial struct {{unitTypeName}} + : IEquatable<{{unitTypeName}}> +#if NET7_0_OR_GREATER + , IEqualityOperators<{{unitTypeName}}, {{unitTypeName}}, bool> +#endif +"""); + if (prop.HasFlag(UnitGenerateOptions.Comparable) && + !prop.HasFlag(UnitGenerateOptions.WithoutComparisonOperator)) + { + sb.AppendLine($$""" + , IComparable<{{unitTypeName}}> +#if NET7_0_OR_GREATER + , IComparisonOperators<{{unitTypeName}}, {{unitTypeName}}, bool> +#endif +"""); + } + if (prop.HasFlag(UnitGenerateOptions.ArithmeticOperator)) + { + sb.AppendLine("#if NET7_0_OR_GREATER"); + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Addition)) + { + sb.AppendLine($$""" + , IAdditionOperators<{{unitTypeName}}, {{unitTypeName}}, {{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Subtraction)) + { + sb.AppendLine($$""" + , ISubtractionOperators<{{unitTypeName}}, {{unitTypeName}}, {{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Multiply)) + { + sb.AppendLine($$""" + , IMultiplyOperators<{{unitTypeName}}, {{unitTypeName}}, {{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Division)) + { + sb.AppendLine($$""" + , IDivisionOperators<{{unitTypeName}}, {{unitTypeName}}, {{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Multiply) || + prop.HasArithmeticOperator(UnitArithmeticOperators.Division)) + { + sb.AppendLine($$""" + , IUnaryPlusOperators<{{unitTypeName}}, {{unitTypeName}}> + , IUnaryNegationOperators<{{unitTypeName}}, {{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Increment)) + { + sb.AppendLine($$""" + , IIncrementOperators<{{unitTypeName}}> +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Decrement)) + { + sb.AppendLine($$""" + , IDecrementOperators<{{unitTypeName}}> +"""); + } + sb.AppendLine("#endif"); + } + + sb.AppendLine($$""" { readonly {{innerTypeName}} value; @@ -243,14 +340,15 @@ namespace {{ns}} """); } + if (prop.HasFlag(UnitGenerateOptions.Validate)) { - sb.AppendLine($$""" + sb.AppendLine(""" private partial void Validate(); - + """); } - + var convertModifier = prop.HasFlag(UnitGenerateOptions.ImplicitOperator) ? "implicit" : "explicit"; sb.AppendLine($$""" public static {{convertModifier}} operator {{innerTypeName}}({{unitTypeName}} value) @@ -283,6 +381,16 @@ public override bool Equals(object obj) return value.Equals(obj); } + + public static bool operator ==({{unitTypeName}} x, {{unitTypeName}} y) + { + return x.value.Equals(y.value); + } + + public static bool operator !=({{unitTypeName}} x, {{unitTypeName}} y) + { + return !x.value.Equals(y.value); + } public override int GetHashCode() { @@ -302,7 +410,7 @@ public override string ToString() } else { - sb.AppendLine($$""" + sb.AppendLine(""" public override string ToString() { return value.ToString(); @@ -310,18 +418,7 @@ public override string ToString() """); } - sb.AppendLine($$""" - public static bool operator ==(in {{unitTypeName}} x, in {{unitTypeName}} y) - { - return x.value.Equals(y.value); - } - public static bool operator !=(in {{unitTypeName}} x, in {{unitTypeName}} y) - { - return !x.value.Equals(y.value); - } - -"""); if (prop.IsGuid()) { sb.AppendLine($$""" @@ -357,11 +454,12 @@ public override string ToString() """); } - + if (prop.HasFlag(UnitGenerateOptions.ParseMethod)) { sb.AppendLine(""" // UnitGenerateOptions.ParseMethod + """); if (prop.IsString()) { @@ -384,7 +482,7 @@ public static bool TryParse(string s, out {{unitTypeName}} result) return false; } } - + """); } else @@ -408,7 +506,7 @@ public static bool TryParse(string s, out {{unitTypeName}} result) return false; } } - + """); } } @@ -426,7 +524,7 @@ public static bool TryParse(string s, out {{unitTypeName}} result) { return new {{unitTypeName}}(Math.Max(x.value, y.value)); } - + """); } @@ -455,10 +553,14 @@ public static bool TryParse(string s, out {{unitTypeName}} result) if (prop.HasFlag(UnitGenerateOptions.ArithmeticOperator)) { - sb.AppendLine($$""" + sb.AppendLine(""" // UnitGenerateOptions.ArithmeticOperator - - public static {{unitTypeName}} operator +(in {{unitTypeName}} x, in {{unitTypeName}} y) + +"""); + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Addition)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator +({{unitTypeName}} x, {{unitTypeName}} y) { checked { @@ -466,7 +568,12 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator -(in {{unitTypeName}} x, in {{unitTypeName}} y) +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Subtraction)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator -({{unitTypeName}} x, {{unitTypeName}} y) { checked { @@ -474,7 +581,21 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator *(in {{unitTypeName}} x, in {{unitTypeName}} y) +"""); + } + + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Multiply) || + prop.HasArithmeticOperator(UnitArithmeticOperators.Division)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator +({{unitTypeName}} value) => new(({{innerTypeName}})(+value.value)); + public static {{unitTypeName}} operator -({{unitTypeName}} value) => new(({{innerTypeName}})(-value.value)); + +"""); + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Multiply)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator *({{unitTypeName}} x, {{unitTypeName}} y) { checked { @@ -482,39 +603,62 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator /(in {{unitTypeName}} x, in {{unitTypeName}} y) +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Division)) + { + sb.AppendLine($$""" + + public static {{unitTypeName}} operator /({{unitTypeName}} x, {{unitTypeName}} y) { checked { return new {{unitTypeName}}(({{innerTypeName}})(x.value / y.value)); } } - -"""); - } - if (prop.HasFlag(UnitGenerateOptions.ValueArithmeticOperator)) - { - sb.AppendLine($$""" - // UnitGenerateOptions.ValueArithmeticOperator +"""); + } + } // End Multiply, Division - public static {{unitTypeName}} operator ++(in {{unitTypeName}} x) + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Increment)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator ++({{unitTypeName}} x) { checked { - return new {{unitTypeName}}(({{innerTypeName}})(x.value + 1)); + return new {{unitTypeName}}(({{innerTypeName}})(({{innerTypeName}})(x.value + 1))); } } - public static {{unitTypeName}} operator --(in {{unitTypeName}} x) +"""); + } + if (prop.HasArithmeticOperator(UnitArithmeticOperators.Decrement)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator --({{unitTypeName}} x) { checked { - return new {{unitTypeName}}(({{innerTypeName}})(x.value - 1)); + return new {{unitTypeName}}(({{innerTypeName}})(({{innerTypeName}})(x.value - 1))); } } - public static {{unitTypeName}} operator +(in {{unitTypeName}} x, in {{innerTypeName}} y) +"""); + } + } // End ArithmeticOperator + + if (prop.HasFlag(UnitGenerateOptions.ValueArithmeticOperator)) + { + sb.AppendLine(""" + // UnitGenerateOptions.ValueArithmeticOperator + +"""); + if (prop.HasValueArithmeticOperator(UnitArithmeticOperators.Addition)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator +({{unitTypeName}} x, {{innerTypeName}} y) { checked { @@ -522,7 +666,12 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator -(in {{unitTypeName}} x, in {{innerTypeName}} y) +"""); + } + if (prop.HasValueArithmeticOperator(UnitArithmeticOperators.Subtraction)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator -({{unitTypeName}} x, {{innerTypeName}} y) { checked { @@ -530,7 +679,12 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator *(in {{unitTypeName}} x, in {{innerTypeName}} y) +"""); + } + if (prop.HasValueArithmeticOperator(UnitArithmeticOperators.Multiply)) + { + sb.AppendLine($$""" + public static {{unitTypeName}} operator *({{unitTypeName}} x, {{innerTypeName}} y) { checked { @@ -538,7 +692,13 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } } - public static {{unitTypeName}} operator /(in {{unitTypeName}} x, in {{innerTypeName}} y) +"""); + } + if (prop.HasValueArithmeticOperator(UnitArithmeticOperators.Division)) + { + sb.AppendLine($$""" + + public static {{unitTypeName}} operator /({{unitTypeName}} x, {{innerTypeName}} y) { checked { @@ -547,7 +707,8 @@ public static bool TryParse(string s, out {{unitTypeName}} result) } """); - } + } + } // End ValueArithmeticOperator if (prop.HasFlag(UnitGenerateOptions.Comparable)) { @@ -558,34 +719,33 @@ public int CompareTo({{unitTypeName}} other) { return value.CompareTo(other.value); } - """); - if (!prop.HasFlag(UnitGenerateOptions.WithoutComparisonOperator)) - { - sb.AppendLine($$""" - public static bool operator >(in {{unitTypeName}} x, in {{unitTypeName}} y) + } + if (prop.HasFlag(UnitGenerateOptions.Comparable) && !prop.HasFlag(UnitGenerateOptions.WithoutComparisonOperator)) + { + sb.AppendLine($$""" + public static bool operator >({{unitTypeName}} x, {{unitTypeName}} y) { return x.value > y.value; } - public static bool operator <(in {{unitTypeName}} x, in {{unitTypeName}} y) + public static bool operator <({{unitTypeName}} x, {{unitTypeName}} y) { return x.value < y.value; } - public static bool operator >=(in {{unitTypeName}} x, in {{unitTypeName}} y) + public static bool operator >=({{unitTypeName}} x, {{unitTypeName}} y) { return x.value >= y.value; } - public static bool operator <=(in {{unitTypeName}} x, in {{unitTypeName}} y) + public static bool operator <=({{unitTypeName}} x, {{unitTypeName}} y) { return x.value <= y.value; } - + """); - } // End ComparisonOperator - } // End Comparable + } if (prop.HasFlag(UnitGenerateOptions.JsonConverter)) { @@ -665,7 +825,7 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, {{unitTypeName}} { return new {{unitTypeName}}({{innerTypeName}}.Parse(reader.GetString())); } - + """); } else if (prop.IsString()) @@ -680,7 +840,7 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, {{unitTypeName}} { return new {{unitTypeName}}(reader.GetString()); } - + """); } else @@ -696,10 +856,10 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, {{unitTypeName}} return new {{unitTypeName}}({{innerTypeName}}.Parse(reader.GetString())); } -"""); +"""); } } // End JsonConverterDictionaryKeySupport - + sb.AppendLine($$""" } @@ -777,10 +937,11 @@ public class {{unitTypeName}}ValueConverter : Microsoft.EntityFrameworkCore.Stor """); } // End EntityFrameworkValueConverter - - + + sb.AppendLine($$""" // Default + private class {{unitTypeName}}TypeConverter : System.ComponentModel.TypeConverter { private static readonly Type WrapperType = typeof({{unitTypeName}}); @@ -856,17 +1017,25 @@ struct UnitOfAttributeProperty { public ITypeSymbol Type { get; set; } public UnitGenerateOptions Options { get; set; } + public UnitArithmeticOperators ArithmeticOperators { get; set; } public string? ToStringFormat { get; set; } public string TypeName => Type.ToString(); - + public bool IsString() => TypeName is "string"; public bool IsBool() => TypeName is "bool"; public bool IsUlid() => TypeName is "Ulid" or "System.Ulid"; public bool IsGuid() => TypeName is "Guid" or "System.Guid"; - - public bool HasFlag(UnitGenerateOptions options) + + public bool HasFlag(UnitGenerateOptions options) => Options.HasFlag(options); + + public bool HasArithmeticOperator(UnitArithmeticOperators op) { - return Options.HasFlag(options); + return HasFlag(UnitGenerateOptions.ArithmeticOperator) && ArithmeticOperators.HasFlag(op); + } + + public bool HasValueArithmeticOperator(UnitArithmeticOperators op) + { + return HasFlag(UnitGenerateOptions.ValueArithmeticOperator) && ArithmeticOperators.HasFlag(op); } public DbType GetDbType() @@ -936,4 +1105,4 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode) } } } -} \ No newline at end of file +} diff --git a/src/UnitGenerator/UnitGenerateOptions.cs b/src/UnitGenerator/UnitGenerateOptions.cs index 5dd7da8..0051a7f 100644 --- a/src/UnitGenerator/UnitGenerateOptions.cs +++ b/src/UnitGenerator/UnitGenerateOptions.cs @@ -2,7 +2,7 @@ namespace UnitGenerator { - // same as Generated Options(check UnitOfAttributeTemplate.tt). + // same as Generated Options(check SourceGenerator.cs). [Flags] internal enum UnitGenerateOptions { @@ -22,4 +22,16 @@ internal enum UnitGenerateOptions JsonConverterDictionaryKeySupport = 1 << 12, Normalize = 1 << 13, } + + [Flags] + internal enum UnitArithmeticOperators + { + All = Addition | Subtraction | Multiply | Division | Increment | Decrement, + Addition = 1, + Subtraction = 1 << 1, + Multiply = 1 << 2, + Division = 1 << 3, + Increment = 1 << 4, + Decrement = 1 << 5, + } }