Skip to content

Commit 1ceec5c

Browse files
committed
Support System.IFormattable/System.IParsable
1 parent ad13a7c commit 1ceec5c

File tree

8 files changed

+165
-5
lines changed

8 files changed

+165
-5
lines changed

sandbox/FileGenerate/SimplePrimitive.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public readonly partial struct B
1212
{
1313
}
1414

15-
[UnitOf(typeof(int), UnitGenerateOptions.Comparable | UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator)]
15+
[UnitOf(typeof(int), UnitGenerateOptions.Comparable | UnitGenerateOptions.ArithmeticOperator | UnitGenerateOptions.ValueArithmeticOperator | UnitGenerateOptions.ParseMethod)]
1616
public readonly partial struct C
1717
{
1818
}

sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.A.g.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ readonly partial struct A
1515
#if NET7_0_OR_GREATER
1616
, IEqualityOperators<A, A, bool>
1717
#endif
18+
, IFormattable
1819
{
1920
readonly int value;
2021

@@ -73,6 +74,8 @@ public override int GetHashCode()
7374

7475
public override string ToString() => value.ToString();
7576

77+
public string ToString(string? format, IFormatProvider? formatProvider) => value.ToString(format, formatProvider);
78+
7679
// Default
7780

7881
private class ATypeConverter : System.ComponentModel.TypeConverter

sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.Aa.g.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ readonly partial struct Aa
1515
#if NET7_0_OR_GREATER
1616
, IEqualityOperators<Aa, Aa, bool>
1717
#endif
18+
, IFormattable
1819
{
1920
readonly int value;
2021

@@ -73,6 +74,8 @@ public override int GetHashCode()
7374

7475
public override string ToString() => value.ToString();
7576

77+
public string ToString(string? format, IFormatProvider? formatProvider) => value.ToString(format, formatProvider);
78+
7679
// Default
7780

7881
private class AaTypeConverter : System.ComponentModel.TypeConverter

sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.C.g.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ readonly partial struct C
1919
#if NET7_0_OR_GREATER
2020
, IComparisonOperators<C, C, bool>
2121
#endif
22+
#if NET7_0_OR_GREATER
23+
, IParsable<C>
24+
#endif
25+
, IFormattable
2226
#if NET7_0_OR_GREATER
2327
, IAdditionOperators<C, C, C>
2428
, ISubtractionOperators<C, C, C>
@@ -87,6 +91,48 @@ public override int GetHashCode()
8791

8892
public override string ToString() => value.ToString();
8993

94+
public string ToString(string? format, IFormatProvider? formatProvider) => value.ToString(format, formatProvider);
95+
96+
// UnitGenerateOptions.ParseMethod
97+
98+
public static C Parse(string s)
99+
{
100+
return new C(int.Parse(s));
101+
}
102+
103+
public static bool TryParse(string s, out C result)
104+
{
105+
if (int.TryParse(s, out var r))
106+
{
107+
result = new C(r);
108+
return true;
109+
}
110+
else
111+
{
112+
result = default(C);
113+
return false;
114+
}
115+
}
116+
117+
public static C Parse(string s, IFormatProvider? provider)
118+
{
119+
return new C(int.Parse(s));
120+
}
121+
122+
public static bool TryParse(string s, IFormatProvider? provider, out C result)
123+
{
124+
if (int.TryParse(s, out var r))
125+
{
126+
result = new C(r);
127+
return true;
128+
}
129+
else
130+
{
131+
result = default(C);
132+
return false;
133+
}
134+
}
135+
90136
// UnitGenerateOptions.ArithmeticOperator
91137

92138
public static C operator +(C x, C y)

sandbox/Generated/UnitGenerator/UnitGenerator.SourceGenerator/FileGenerate.Cc.g.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ readonly partial struct Cc
1919
#if NET7_0_OR_GREATER
2020
, IComparisonOperators<Cc, Cc, bool>
2121
#endif
22+
, IFormattable
2223
#if NET7_0_OR_GREATER
2324
, IAdditionOperators<Cc, Cc, Cc>
2425
, ISubtractionOperators<Cc, Cc, Cc>
@@ -87,6 +88,8 @@ public override int GetHashCode()
8788

8889
public override string ToString() => value.ToString();
8990

91+
public string ToString(string? format, IFormatProvider? formatProvider) => value.ToString(format, formatProvider);
92+
9093
// UnitGenerateOptions.ArithmeticOperator
9194

9295
public static Cc operator +(Cc x, Cc y)

src/UnitGenerator/ReferenceSymbols.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using Microsoft.CodeAnalysis;
3+
4+
namespace UnitGenerator;
5+
6+
class ReferenceSymbols
7+
{
8+
public static ReferenceSymbols Create(Compilation compilation)
9+
{
10+
return new ReferenceSymbols
11+
{
12+
IParsableInterface = compilation.GetTypeByMetadataName("System.IParsable`1")!,
13+
IFormattableInterface = compilation.GetTypeByMetadataName("System.IFormattable")!,
14+
GuidType = compilation.GetTypeByMetadataName("System.Guid"),
15+
UlidType = compilation.GetTypeByMetadataName("System.Ulid"),
16+
};
17+
}
18+
19+
public INamedTypeSymbol IParsableInterface { get; private set; } = default!;
20+
public INamedTypeSymbol IFormattableInterface { get; private set; } = default!;
21+
public INamedTypeSymbol? UlidType { get; private set; }
22+
public INamedTypeSymbol? GuidType { get; private set; }
23+
}

src/UnitGenerator/SourceGenerator.cs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ public void Execute(GeneratorExecutionContext context)
2525
var receiver = context.SyntaxReceiver as SyntaxReceiver;
2626
if (receiver == null) return;
2727

28+
var symbols = ReferenceSymbols.Create(context.Compilation);
2829
var list = new List<(StructDeclarationSyntax, UnitOfAttributeProperty)>();
2930
foreach (var (type, attr, targetType) in receiver.Targets)
3031
{
3132
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
3233

3334
// retrieve attribute parameter
34-
var prop = new UnitOfAttributeProperty { ArithmeticOperators = UnitArithmeticOperators.All };
35+
var prop = new UnitOfAttributeProperty
36+
{
37+
Symbols = symbols,
38+
ArithmeticOperators = UnitArithmeticOperators.All
39+
};
3540

3641
if(targetType is not null)
3742
{
@@ -276,6 +281,21 @@ readonly partial struct {{unitTypeName}}
276281
#endif
277282
""");
278283
}
284+
if (prop.HasFlag(UnitGenerateOptions.ParseMethod) && prop.HasIParsableInterface())
285+
{
286+
sb.AppendLine($$"""
287+
#if NET7_0_OR_GREATER
288+
, IParsable<{{unitTypeName}}>
289+
#endif
290+
""");
291+
}
292+
if (prop.HasIFormattableInterface())
293+
{
294+
sb.AppendLine($$"""
295+
, IFormattable
296+
""");
297+
}
298+
279299
if (prop.HasFlag(UnitGenerateOptions.ArithmeticOperator))
280300
{
281301
sb.AppendLine("#if NET7_0_OR_GREATER");
@@ -453,6 +473,14 @@ public override int GetHashCode()
453473
}
454474
}
455475

476+
if (prop.HasIParsableInterface())
477+
{
478+
sb.AppendLine($$"""
479+
public string ToString(string? format, IFormatProvider? formatProvider) => value.ToString(format, formatProvider);
480+
481+
""");
482+
}
483+
456484
if (prop.IsGuid())
457485
{
458486
sb.AppendLine($$"""
@@ -543,7 +571,34 @@ public static bool TryParse(string s, out {{unitTypeName}} result)
543571
544572
""");
545573
}
574+
575+
if (prop.HasIParsableInterface())
576+
{
577+
sb.AppendLine($$"""
578+
public static {{unitTypeName}} Parse(string s, IFormatProvider? provider)
579+
{
580+
return new {{unitTypeName}}({{innerTypeName}}.Parse(s));
581+
}
582+
583+
public static bool TryParse(string s, IFormatProvider? provider, out {{unitTypeName}} result)
584+
{
585+
if ({{innerTypeName}}.TryParse(s, out var r))
586+
{
587+
result = new {{unitTypeName}}(r);
588+
return true;
589+
}
590+
else
591+
{
592+
result = default({{unitTypeName}});
593+
return false;
594+
}
595+
}
596+
597+
""");
598+
599+
}
546600
}
601+
547602
if (prop.HasFlag(UnitGenerateOptions.MinMaxMethod))
548603
{
549604
sb.AppendLine($$"""
@@ -1049,6 +1104,7 @@ public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext co
10491104

10501105
struct UnitOfAttributeProperty
10511106
{
1107+
public ReferenceSymbols Symbols { get; set; }
10521108
public ITypeSymbol Type { get; set; }
10531109
public UnitGenerateOptions Options { get; set; }
10541110
public UnitArithmeticOperators ArithmeticOperators { get; set; }
@@ -1057,8 +1113,8 @@ struct UnitOfAttributeProperty
10571113

10581114
public bool IsString() => TypeName is "string";
10591115
public bool IsBool() => TypeName is "bool";
1060-
public bool IsUlid() => TypeName is "Ulid" or "System.Ulid";
1061-
public bool IsGuid() => TypeName is "Guid" or "System.Guid";
1116+
public bool IsUlid() => SymbolEqualityComparer.Default.Equals(Type, Symbols.UlidType);
1117+
public bool IsGuid() => SymbolEqualityComparer.Default.Equals(Type, Symbols.GuidType);
10621118

10631119
public bool HasFlag(UnitGenerateOptions options) => Options.HasFlag(options);
10641120

@@ -1072,6 +1128,32 @@ public bool HasValueArithmeticOperator(UnitArithmeticOperators op)
10721128
return HasFlag(UnitGenerateOptions.ValueArithmeticOperator) && ArithmeticOperators.HasFlag(op);
10731129
}
10741130

1131+
public bool HasIParsableInterface()
1132+
{
1133+
foreach (var x in Type.AllInterfaces)
1134+
{
1135+
if (x.IsGenericType &&
1136+
SymbolEqualityComparer.Default.Equals(x.ConstructedFrom, Symbols.IParsableInterface) &&
1137+
SymbolEqualityComparer.Default.Equals(x.TypeArguments[0], Type))
1138+
{
1139+
return true;
1140+
}
1141+
}
1142+
return false;
1143+
}
1144+
1145+
public bool HasIFormattableInterface()
1146+
{
1147+
foreach (var x in Type.AllInterfaces)
1148+
{
1149+
if (SymbolEqualityComparer.Default.Equals(x, Symbols.IFormattableInterface))
1150+
{
1151+
return true;
1152+
}
1153+
}
1154+
return false;
1155+
}
1156+
10751157
public DbType GetDbType()
10761158
{
10771159
return TypeName switch

src/UnitGenerator/UnitGenerator.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5-
<LangVersion>preview</LangVersion>
5+
<LangVersion>12</LangVersion>
66
<Nullable>enable</Nullable>
77
<NoWarn>$(NoWarn);CS1591</NoWarn>
88
<IsRoslynComponent>true</IsRoslynComponent>

0 commit comments

Comments
 (0)