Skip to content

Commit 34ef3e3

Browse files
committed
readying equatable command
1 parent 17aa984 commit 34ef3e3

File tree

7 files changed

+114
-20
lines changed

7 files changed

+114
-20
lines changed

src/ConsoleAppFramework/Command.cs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
using Microsoft.CodeAnalysis;
2-
using System;
3-
using System.Data.Common;
4-
using System.Diagnostics.CodeAnalysis;
5-
using System.Reflection;
6-
using System.Reflection.Metadata;
72
using System.Text;
83

94
namespace ConsoleAppFramework;
@@ -28,12 +23,12 @@ public record class Command
2823
public bool IsRootCommand => Name == "";
2924
public required string Name { get; init; }
3025

31-
public required CommandParameter[] Parameters { get; init; }
26+
public required EquatableArray<CommandParameter> Parameters { get; init; }
3227
public required string Description { get; init; }
3328
public required MethodKind MethodKind { get; init; }
3429
public required DelegateBuildType DelegateBuildType { get; init; }
3530
public CommandMethodInfo? CommandMethodInfo { get; set; } // can set...!
36-
public required FilterInfo[] Filters { get; init; }
31+
public required EquatableArray<FilterInfo> Filters { get; init; }
3732
public bool HasFilter => Filters.Length != 0;
3833

3934
public string? BuildDelegateSignature(out string? delegateType)
@@ -148,7 +143,7 @@ public string BuildDelegateType(string delegateName)
148143

149144
public record class CommandParameter
150145
{
151-
public required ITypeSymbol Type { get; init; }
146+
public required EquatableTypeSymbol Type { get; init; }
152147
public required Location Location { get; init; }
153148
public required WellKnownTypes WellKnownTypes { get; init; }
154149
public required bool IsNullableReference { get; init; }
@@ -157,7 +152,7 @@ public record class CommandParameter
157152
public required string OriginalParameterName { get; init; }
158153
public required bool HasDefaultValue { get; init; }
159154
public object? DefaultValue { get; init; }
160-
public required ITypeSymbol? CustomParserType { get; init; }
155+
public required EquatableTypeSymbol? CustomParserType { get; init; }
161156
public required bool IsFromServices { get; init; }
162157
public required bool IsConsoleAppContext { get; init; }
163158
public required bool IsCancellationToken { get; init; }
@@ -166,15 +161,15 @@ public record class CommandParameter
166161
public required bool HasValidation { get; init; }
167162
public required int ArgumentIndex { get; init; } // -1 is not Argument, other than marked as [Argument]
168163
public bool IsArgument => ArgumentIndex != -1;
169-
public required string[] Aliases { get; init; }
164+
public required EquatableArray<string> Aliases { get; init; }
170165
public required string Description { get; init; }
171166
public bool RequireCheckArgumentParsed => !(HasDefaultValue || IsParams || IsFlag);
172167

173168
// increment = false when passed from [Argument]
174169
public string BuildParseMethod(int argCount, string argumentName, bool increment)
175170
{
176171
var incrementIndex = increment ? "!TryIncrementIndex(ref i, args.Length) || " : "";
177-
return Core(Type, false);
172+
return Core(Type.TypeSymbol, false);
178173

179174
string Core(ITypeSymbol type, bool nullable)
180175
{
@@ -360,7 +355,7 @@ public record class CommandMethodInfo
360355
{
361356
public required string TypeFullName { get; init; }
362357
public required string MethodName { get; init; }
363-
public required ITypeSymbol[] ConstructorParameterTypes { get; init; }
358+
public required EquatableArray<EquatableTypeSymbol> ConstructorParameterTypes { get; init; }
364359
public required bool IsIDisposable { get; init; }
365360
public required bool IsIAsyncDisposable { get; init; }
366361

@@ -379,7 +374,7 @@ public string BuildNew()
379374
public record class FilterInfo
380375
{
381376
public required string TypeFullName { get; init; }
382-
public required ITypeSymbol[] ConstructorParameterTypes { get; init; }
377+
public required EquatableArray<EquatableTypeSymbol> ConstructorParameterTypes { get; init; }
383378

384379
FilterInfo()
385380
{
@@ -401,7 +396,7 @@ public record class FilterInfo
401396
var filter = new FilterInfo
402397
{
403398
TypeFullName = type.ToFullyQualifiedFormatDisplayString(),
404-
ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => x.Type).ToArray()
399+
ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbol(x.Type)).ToArray()
405400
};
406401

407402
return filter;

src/ConsoleAppFramework/ConsoleAppGenerator.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,23 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
756756
sourceProductionContext.AddSource("ConsoleApp.Builder.Help.g.cs", help.ToString());
757757
}
758758

759+
class CommandContext(Command command, bool isAsync, DiagnosticReporter diagnosticReporter) : IEquatable<CommandContext>
760+
{
761+
public Command Command => command;
762+
public DiagnosticReporter DiagnosticReporter => diagnosticReporter;
763+
public bool IsAsync => isAsync;
764+
765+
public bool Equals(CommandContext other)
766+
{
767+
// has diagnostics, always go to modified(don't cache)
768+
if (diagnosticReporter.HasDiagnostics || other.DiagnosticReporter.HasDiagnostics) return false;
769+
770+
if (isAsync != other.IsAsync) return false;
771+
772+
return command.Equals(other.Command);
773+
}
774+
}
775+
759776
readonly struct RunContext(InvocationExpressionSyntax node, SemanticModel model) : IEquatable<RunContext>
760777
{
761778
public InvocationExpressionSyntax Node => node;

src/ConsoleAppFramework/Emitter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
109109
sb.AppendLine($"var arg{i} = ({type})ServiceProvider!.GetService(typeof({type}))!;");
110110
}
111111
}
112-
sb.AppendLineIfExists(command.Parameters);
112+
sb.AppendLineIfExists(command.Parameters.AsSpan());
113113

114114
using (command.HasFilter ? sb.Nop : sb.BeginBlock("try"))
115115
{
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Collections;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace ConsoleAppFramework;
5+
6+
public readonly struct EquatableArray<T> : IEquatable<EquatableArray<T>>, IEnumerable<T>
7+
where T : IEquatable<T>
8+
{
9+
readonly T[]? array;
10+
11+
public EquatableArray() // for collection literal []
12+
{
13+
array = [];
14+
}
15+
16+
public EquatableArray(T[] array)
17+
{
18+
this.array = array;
19+
}
20+
21+
public static implicit operator EquatableArray<T>(T[] array)
22+
{
23+
return new EquatableArray<T>(array);
24+
}
25+
26+
public ref readonly T this[int index]
27+
{
28+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
29+
get => ref array![index];
30+
}
31+
32+
public int Length => array!.Length;
33+
34+
public ReadOnlySpan<T> AsSpan()
35+
{
36+
return array.AsSpan();
37+
}
38+
39+
public ReadOnlySpan<T>.Enumerator GetEnumerator()
40+
{
41+
return AsSpan().GetEnumerator();
42+
}
43+
44+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
45+
{
46+
return array.AsEnumerable().GetEnumerator();
47+
}
48+
49+
IEnumerator IEnumerable.GetEnumerator()
50+
{
51+
return array.AsEnumerable().GetEnumerator();
52+
}
53+
54+
public bool Equals(EquatableArray<T> other)
55+
{
56+
return AsSpan().SequenceEqual(array.AsSpan());
57+
}
58+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Microsoft.CodeAnalysis;
2+
using System.Collections.Immutable;
3+
4+
namespace ConsoleAppFramework;
5+
6+
public class EquatableTypeSymbol(ITypeSymbol typeSymbol) : IEquatable<EquatableTypeSymbol>
7+
{
8+
// check this two types usage for Equality
9+
public ITypeSymbol TypeSymbol => typeSymbol;
10+
public ImmutableArray<ISymbol> GetMembers() => typeSymbol.GetMembers();
11+
12+
public TypeKind TypeKind { get; } = typeSymbol.TypeKind;
13+
public SpecialType SpecialType { get; } = typeSymbol.SpecialType;
14+
15+
16+
public string ToFullyQualifiedFormatDisplayString() => typeSymbol.ToFullyQualifiedFormatDisplayString();
17+
public string ToDisplayString(NullableFlowState state, SymbolDisplayFormat format) => typeSymbol.ToDisplayString(state, format);
18+
19+
public bool Equals(EquatableTypeSymbol other)
20+
{
21+
// TODO:
22+
return false;
23+
}
24+
}

src/ConsoleAppFramework/Parser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ internal class Parser(DiagnosticReporter context, InvocationExpressionSyntax nod
133133
TypeFullName = type.ToFullyQualifiedFormatDisplayString(),
134134
IsIDisposable = hasIDisposable,
135135
IsIAsyncDisposable = hasIAsyncDisposable,
136-
ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => x.Type).ToArray(),
136+
ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbol(x.Type)).ToArray(),
137137
MethodName = "", // without methodname
138138
};
139139

@@ -348,11 +348,11 @@ internal class Parser(DiagnosticReporter context, InvocationExpressionSyntax nod
348348
IsNullableReference = isNullableReference,
349349
IsConsoleAppContext = isConsoleAppContext,
350350
IsParams = hasParams,
351-
Type = type.Type!,
351+
Type = new EquatableTypeSymbol(type.Type!),
352352
Location = x.GetLocation(),
353353
HasDefaultValue = hasDefault,
354354
DefaultValue = defaultValue,
355-
CustomParserType = customParserType,
355+
CustomParserType = customParserType == null ? null : new EquatableTypeSymbol(customParserType),
356356
HasValidation = hasValidation,
357357
IsCancellationToken = isCancellationToken,
358358
IsFromServices = isFromServices,
@@ -505,7 +505,7 @@ internal class Parser(DiagnosticReporter context, InvocationExpressionSyntax nod
505505
IsConsoleAppContext = isConsoleAppContext,
506506
IsParams = x.IsParams,
507507
Location = x.DeclaringSyntaxReferences[0].GetSyntax().GetLocation(),
508-
Type = x.Type,
508+
Type = new EquatableTypeSymbol(x.Type),
509509
HasDefaultValue = x.HasExplicitDefaultValue,
510510
DefaultValue = x.HasExplicitDefaultValue ? x.ExplicitDefaultValue : null,
511511
CustomParserType = null,

src/ConsoleAppFramework/SourceBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void AppendLine()
5454
builder.AppendLine();
5555
}
5656

57-
public void AppendLineIfExists<T>(T[] values)
57+
public void AppendLineIfExists<T>(ReadOnlySpan<T> values)
5858
{
5959
if (values.Length != 0)
6060
{

0 commit comments

Comments
 (0)