extensions rework pt1
.NET Test / .NET tests (push) Successful in 2m0s

This commit is contained in:
2026-07-13 22:20:47 +04:00
parent 46487a4794
commit 0e7986996f
30 changed files with 1476 additions and 160 deletions
@@ -0,0 +1,210 @@
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
namespace Just.Railway.SourceGen.Executors;
public sealed class TryExtensionsExecutor : IGeneratorExecutor
{
public void Execute(IncrementalGeneratorPostInitializationContext context)
{
var methods = GenerateMethods();
var code = $$"""
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.CodeDom.Compiler;
namespace Just.Railway;
public static partial class Try
{
{{methods}}
}
""";
context.AddSource("Try.Run.g.cs", code);
}
private string GenerateMethods()
{
var sb = new StringBuilder();
for (int i = 0; i <= Constants.MaxResultTupleSize; i++)
{
GenerateMethodsForArgCount(sb, argCount: i);
}
return sb.ToString();
}
private void GenerateMethodsForArgCount(StringBuilder sb, int argCount)
{
var templateArgNames = Enumerable.Range(1, argCount)
.Select(i => $"T{i}")
.ToImmutableArray();
var argNames = Enumerable.Range(1, argCount)
.Select(i => $"arg{i}")
.ToImmutableArray();
string actionTemplateDecl = GenerateTemplateDecl(templateArgNames);
string resultActionTemplateDecl = GenerateTemplateDecl(templateArgNames.Add("Result"));
string funcTemplateDecl = GenerateTemplateDecl(templateArgNames.Add("TResult"));
string resultFuncTemplateDecl = GenerateTemplateDecl(templateArgNames.Add("Result<TResult>"));
string argumentsDeclExpansion = string.Join(", ", templateArgNames.Zip(argNames, (t, n) => $"{t} {n}"));
string argumentsExpansion = string.Join(", ", argNames);
sb.AppendLine($"#region <{string.Join(", ", templateArgNames)}>");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static Result Run{{actionTemplateDecl}}(Action{{actionTemplateDecl}} action{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
action({{argumentsExpansion}});
return Result.Success();
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static Result Run{{actionTemplateDecl}}(Func{{resultActionTemplateDecl}} action{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return action({{argumentsExpansion}});
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static Result<TResult> Run{{funcTemplateDecl}}(Func{{funcTemplateDecl}} func{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return Result.Success(func({{argumentsExpansion}}));
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static Result<TResult> Run{{funcTemplateDecl}}(Func{{resultFuncTemplateDecl}} func{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return func({{argumentsExpansion}});
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
GenerateAsyncMethods(sb, templateArgNames, actionTemplateDecl, funcTemplateDecl, argumentsDeclExpansion, argumentsExpansion, "Task", string.Empty);
GenerateAsyncMethods(sb, templateArgNames, actionTemplateDecl, funcTemplateDecl, argumentsDeclExpansion, argumentsExpansion, "ValueTask", "ValueTask");
sb.AppendLine("#endregion");
}
private static void GenerateAsyncMethods(StringBuilder sb, ImmutableArray<string> templateArgNames, string actionTemplateDecl, string funcTemplateDecl, string argumentsDeclExpansion, string argumentsExpansion, string taskType, string methodSuffix)
{
string actionTaskTemplateDecl = GenerateTemplateDecl(templateArgNames.Add(taskType));
string resultActionTaskTemplateDecl = GenerateTemplateDecl(templateArgNames.Add($"{taskType}<Result>"));
string funcTaskTemplateDecl = GenerateTemplateDecl(templateArgNames.Add($"{taskType}<TResult>"));
string resultFuncTaskTemplateDecl = GenerateTemplateDecl(templateArgNames.Add($"{taskType}<Result<TResult>>"));
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static async {{taskType}}<Result> Run{{methodSuffix}}{{actionTemplateDecl}}(Func{{actionTaskTemplateDecl}} action{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
await action({{argumentsExpansion}}).ConfigureAwait(false);
return Result.Success();
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static async {{taskType}}<Result> Run{{methodSuffix}}{{actionTemplateDecl}}(Func{{resultActionTaskTemplateDecl}} action{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return await action({{argumentsExpansion}}).ConfigureAwait(false);
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static async {{taskType}}<Result<TResult>> Run{{methodSuffix}}{{funcTemplateDecl}}(Func{{funcTaskTemplateDecl}} func{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return Result.Success(await func({{argumentsExpansion}}).ConfigureAwait(false));
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
sb.AppendLine($$"""
[PureAttribute]
[GeneratedCodeAttribute("{{nameof(TryExtensionsExecutor)}}", "1.0.0.0")]
public static async {{taskType}}<Result<TResult>> Run{{methodSuffix}}{{funcTemplateDecl}}(Func{{resultFuncTaskTemplateDecl}} func{{TrailingArguments(argumentsDeclExpansion)}})
{
try
{
return await func({{argumentsExpansion}}).ConfigureAwait(false);
}
catch (Exception ex)
{
return Error.New(ex);
}
}
""");
}
private static string TrailingArguments(string argumentsExpansion) => string.IsNullOrEmpty(argumentsExpansion)
? string.Empty
: $", {argumentsExpansion}";
private static string GenerateTemplateDecl(ImmutableArray<string> templateArgNames) => templateArgNames.Length > 0
? $"<{string.Join(", ", templateArgNames)}>"
: string.Empty;
}