From 8211825bef2e79bb2d503f562aa8ddac4e39e30d Mon Sep 17 00:00:00 2001
From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com>
Date: Thu, 25 Dec 2025 19:23:48 +0100
Subject: [PATCH] Add source generator to generate ExecuteAsync overloads
---
.../LeastBacklogStrategy.cs | 4 +
RemoteExec.Client/RemoteExec.Client.csproj | 6 ++
.../RemoteExec.Generators.csproj | 12 +++
.../RemoteExecutorOverloadGenerator.cs | 76 +++++++++++++++++++
RemoteExec.slnx | 1 +
RemoteExec/Program.cs | 10 ++-
6 files changed, 108 insertions(+), 1 deletion(-)
create mode 100644 RemoteExec.Generators/RemoteExec.Generators.csproj
create mode 100644 RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs
diff --git a/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs b/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs
index f39f8b7..fd61274 100644
--- a/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs
+++ b/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs
@@ -1,7 +1,11 @@
namespace RemoteExec.Client.LoadBalancingStrategies;
+///
+/// A load balancing strategy that selects servers based on local backlog.
+///
public class LeastBacklogStrategy : ILoadBalancingStrategy
{
+ ///
public ServerConnection? SelectServer(IEnumerable availableServers)
{
return availableServers.MinBy(s => s.TaskChannel.Reader.Count);
diff --git a/RemoteExec.Client/RemoteExec.Client.csproj b/RemoteExec.Client/RemoteExec.Client.csproj
index c43c42c..fa5dd3f 100644
--- a/RemoteExec.Client/RemoteExec.Client.csproj
+++ b/RemoteExec.Client/RemoteExec.Client.csproj
@@ -16,4 +16,10 @@
+
+
+
+
diff --git a/RemoteExec.Generators/RemoteExec.Generators.csproj b/RemoteExec.Generators/RemoteExec.Generators.csproj
new file mode 100644
index 0000000..fdf27f7
--- /dev/null
+++ b/RemoteExec.Generators/RemoteExec.Generators.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+ latest
+ true
+
+
+
+
+
+
diff --git a/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs b/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs
new file mode 100644
index 0000000..fa55728
--- /dev/null
+++ b/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs
@@ -0,0 +1,76 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+using System.Linq;
+using System.Text;
+
+namespace RemoteExec.Generators;
+
+[Generator]
+public class RemoteExecutorOverloadGenerator : IIncrementalGenerator
+{
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+ context.RegisterPostInitializationOutput(ctx =>
+ {
+ string source = GenerateOverloads(16);
+ ctx.AddSource("RemoteExecutor.Overloads.g.cs", SourceText.From(source, Encoding.UTF8));
+ });
+ }
+
+ private static string GenerateOverloads(int maxArgs)
+ {
+ StringBuilder sb = new StringBuilder();
+ _ = sb.AppendLine("// ");
+ _ = sb.AppendLine("using System;");
+ _ = sb.AppendLine("using System.Threading;");
+ _ = sb.AppendLine("using System.Threading.Tasks;");
+ _ = sb.AppendLine();
+ _ = sb.AppendLine("namespace RemoteExec.Client;");
+ _ = sb.AppendLine();
+ _ = sb.AppendLine("public partial class RemoteExecutor");
+ _ = sb.AppendLine("{");
+
+ for (int i = 0; i <= maxArgs; i++)
+ {
+ // T1, T2, T3...
+ string typeParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n}"));
+ // T1 arg1, T2 arg2...
+ string methodParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n} arg{n}"));
+ // arg1, arg2...
+ string callArgs = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"arg{n}!"));
+
+ // Async overloads (Task)
+ string genericBracket = i == 0 ? "" : $"<{typeParams}, TResult>";
+ string funcType = i == 0 ? "Func>" : $"Func<{typeParams}, Task>";
+
+ _ = sb.AppendLine($$"""
+ /// Generates a remote execution call for {{i}} async arguments.
+ public async Task ExecuteAsync{{genericBracket}}(
+ {{funcType}} @delegate,
+ {{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default)
+ {
+ return await ExecuteAsync<{{funcType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}});
+ }
+
+ """);
+
+ // Sync overloads (Func)
+ string syncFuncType = i == 0 ? "Func" : $"Func<{typeParams}, TResult>";
+
+ _ = sb.AppendLine($$"""
+ /// Generates a remote execution call for {{i}} synchronous arguments.
+ public async Task ExecuteAsync{{genericBracket}}(
+ {{syncFuncType}} @delegate,
+ {{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default)
+ {
+ return await ExecuteAsync<{{syncFuncType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}});
+ }
+
+ """);
+ }
+
+ _ = sb.AppendLine("}");
+ return sb.ToString();
+ }
+}
\ No newline at end of file
diff --git a/RemoteExec.slnx b/RemoteExec.slnx
index e89b600..a2ab5cc 100644
--- a/RemoteExec.slnx
+++ b/RemoteExec.slnx
@@ -1,6 +1,7 @@
+
diff --git a/RemoteExec/Program.cs b/RemoteExec/Program.cs
index 352e191..4c99952 100644
--- a/RemoteExec/Program.cs
+++ b/RemoteExec/Program.cs
@@ -22,8 +22,11 @@ await singleHostExecutor.StartAsync();
await Parallel.ForAsync(0, 1000, async (i, cancellationToken) =>
{
- int r = await singleHostExecutor.ExecuteAsync>, int>(Multiply, i, i + 1);
+ int r = await singleHostExecutor.ExecuteAsync(Multiply, i, i + 1, cancellationToken);
Console.WriteLine($"Multiply {i} * {i + 1} = {r}");
+
+ int s = await singleHostExecutor.ExecuteAsync(Add, i, i + 1, cancellationToken);
+ Console.WriteLine($"Add {i} + {i + 1} = {s}");
});
await singleHostExecutor.StopAsync();
@@ -32,4 +35,9 @@ static async Task Multiply(int x, int y)
{
await Task.Delay(Random.Shared.Next(100, 500));
return x.Multiply(y);
+}
+
+static int Add(int x, int y)
+{
+ return x + y;
}
\ No newline at end of file