using AyCode.Core.Benchmarks.Workloads.Scenarios;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
namespace AyCode.Core.Serializers.Console;
///
/// Interactive console menu for the benchmark application. Shown when the user runs without CLI args:
/// top-level layer/mode selection + nested Settings sub-menus (iteration counts, wire mode, charset).
/// All settings mutate in place; the menu loop returns control to the
/// caller (Program.Main) once the user picks a benchmark layer or quits.
///
internal static class Menu
{
///
/// Interactive menu shown when no CLI args. Returns the (layer, serializerMode) tuple, or null on Quit.
/// Loops on settings-changes ([S]) — user is returned to this menu after modifying iteration counts.
///
internal static (BenchmarkLayer layer, SerializerSelectionMode serializerMode)? ShowInteractiveMenu()
{
while (true)
{
System.Console.WriteLine();
System.Console.WriteLine("╔══════════════════════════════════════════════════════════╗");
System.Console.WriteLine("║ AcBinary Benchmark Suite ║");
System.Console.WriteLine("╚══════════════════════════════════════════════════════════╝");
System.Console.WriteLine();
System.Console.WriteLine("Select benchmark layer:");
System.Console.WriteLine();
System.Console.WriteLine(" [1] Core — daily iteration");
System.Console.WriteLine(" [2] Comprehensive — release validation");
System.Console.WriteLine(" [3] Edge cases — refactor verification");
System.Console.WriteLine(" [A] All layers");
System.Console.WriteLine(" [F] FastestByte — AcBinary FastMode Byte[] vs MemoryPack Byte[] only (tight optimization loop)");
System.Console.WriteLine(" [P] AsyncPipe — streaming I/O isolation (only AsyncPipe, all test data)");
System.Console.WriteLine($" [S] Settings — Iteration / WireMode (current: {Configuration.SelectedWireMode})");
System.Console.WriteLine(" [Q] Quit");
System.Console.Write("\nSelection: ");
var key = System.Console.ReadKey(intercept: false).KeyChar;
System.Console.WriteLine();
switch (char.ToLower(key))
{
case '1': return (BenchmarkLayer.Core, SerializerSelectionMode.Standard);
case '2': return (BenchmarkLayer.Comprehensive, SerializerSelectionMode.Standard);
case '3': return (BenchmarkLayer.Edge, SerializerSelectionMode.Standard);
case 'a': return (BenchmarkLayer.All, SerializerSelectionMode.Standard);
case 'f': return (BenchmarkLayer.All, SerializerSelectionMode.FastestByte);
case 'p': return (BenchmarkLayer.All, SerializerSelectionMode.AsyncPipe);
case 's':
ShowSettingsMenu();
continue; // re-display the main menu after settings update
case 'q': return null;
default: return (BenchmarkLayer.All, SerializerSelectionMode.Standard);
}
}
}
///
/// Settings sub-menu — dispatches to per-area sub-menus (iteration counts, wire mode, charset).
/// Returns to the caller (which re-displays the main menu) when [B]ack is pressed.
///
private static void ShowSettingsMenu()
{
while (true)
{
System.Console.WriteLine();
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine("Settings");
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine(" [1] Iteration — Warmup / Iterations / Samples");
System.Console.WriteLine($" [2] WireMode — current: {Configuration.SelectedWireMode}");
System.Console.WriteLine($" [3] Charset — current: {Configuration.GetCurrentCharsetName()}");
System.Console.WriteLine(" [B] Back");
System.Console.Write("\nSelection: ");
var key = System.Console.ReadKey(intercept: false).KeyChar;
System.Console.WriteLine();
switch (char.ToLower(key))
{
case '1':
ShowIterationSettingsMenu();
break;
case '2':
ShowWireModeSettingsMenu();
break;
case '3':
ShowCharsetSettingsMenu();
break;
case 'b':
return;
default:
continue;
}
}
}
private static void ShowCharsetSettingsMenu()
{
while (true)
{
System.Console.WriteLine();
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine("Charset settings — long-string suffix profile");
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine($"Current: {Configuration.GetCurrentCharsetName()}");
System.Console.WriteLine();
System.Console.WriteLine(" All *Short = 40 char, all *Long = 280 char (= Short × 7) — length-consistent across charsets.");
System.Console.WriteLine();
System.Console.WriteLine(" [1] Latin1FixAscii — empty suffix; baseline-only short values → FixStrAscii tier");
System.Console.WriteLine(" [2] AsciiShort — 40 char pure ASCII (quic × 8) → StringAscii tier");
System.Console.WriteLine(" [3] AsciiLong — 280 char pure ASCII → StringAscii tier");
System.Console.WriteLine(" [4] Latin1Short — 40 char Hungarian (árví × 8) → StringSmall tier");
System.Console.WriteLine(" [5] Latin1Long — 280 char Hungarian (default) → StringMedium tier");
System.Console.WriteLine(" [6] CjkBmpShort — 40 char CJK BMP (3-byte runs) → StringSmall tier");
System.Console.WriteLine(" [7] CjkBmpLong — 280 char CJK BMP → StringMedium tier");
System.Console.WriteLine(" [8] CyrillicShort — 40 char Cyrillic (2-byte runs) → StringSmall tier");
System.Console.WriteLine(" [9] CyrillicLong — 280 char Cyrillic → StringMedium tier");
System.Console.WriteLine(" [0] MixedShort — 40 char multi-codepage → StringSmall tier");
System.Console.WriteLine(" [A] MixedLong — 280 char multi-codepage → StringMedium tier");
System.Console.WriteLine(" [B] Back");
System.Console.Write("\nSelection: ");
var key = System.Console.ReadKey(intercept: false).KeyChar;
System.Console.WriteLine();
switch (char.ToLower(key))
{
case '1':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1FixAscii;
System.Console.WriteLine("✓ Charset set to Latin1FixAscii");
return;
case '2':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.AsciiShort;
System.Console.WriteLine("✓ Charset set to AsciiShort");
return;
case '3':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.AsciiLong;
System.Console.WriteLine("✓ Charset set to AsciiLong");
return;
case '4':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Short;
System.Console.WriteLine("✓ Charset set to Latin1Short");
return;
case '5':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Long;
System.Console.WriteLine("✓ Charset set to Latin1Long");
return;
case '6':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmpShort;
System.Console.WriteLine("✓ Charset set to CjkBmpShort");
return;
case '7':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmpLong;
System.Console.WriteLine("✓ Charset set to CjkBmpLong");
return;
case '8':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CyrillicShort;
System.Console.WriteLine("✓ Charset set to CyrillicShort");
return;
case '9':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CyrillicLong;
System.Console.WriteLine("✓ Charset set to CyrillicLong");
return;
case '0':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.MixedShort;
System.Console.WriteLine("✓ Charset set to MixedShort");
return;
case 'a':
BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.MixedLong;
System.Console.WriteLine("✓ Charset set to MixedLong");
return;
case 'b':
return;
default:
continue;
}
}
}
private static void ShowIterationSettingsMenu()
{
System.Console.WriteLine();
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine("Iteration settings — press Enter to keep current value");
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine();
Configuration.WarmupIterations = PromptInt("WarmupIterations", Configuration.WarmupIterations, min: 0);
Configuration.TestIterations = PromptInt("TestIterations ", Configuration.TestIterations, min: 1);
Configuration.BenchmarkSamples = PromptInt("BenchmarkSamples", Configuration.BenchmarkSamples, min: 1);
System.Console.WriteLine();
System.Console.WriteLine($"✓ Iteration settings updated: Warmup={Configuration.WarmupIterations} | Iterations={Configuration.TestIterations} | Samples={Configuration.BenchmarkSamples}");
}
private static void ShowWireModeSettingsMenu()
{
while (true)
{
System.Console.WriteLine();
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine("WireMode settings");
System.Console.WriteLine("─────────────────────────────────────────────");
System.Console.WriteLine($"Current: {Configuration.SelectedWireMode}");
System.Console.WriteLine(" [1] Compact");
System.Console.WriteLine(" [2] Fast");
System.Console.WriteLine(" [B] Back");
System.Console.Write("\nSelection: ");
var key = System.Console.ReadKey(intercept: false).KeyChar;
System.Console.WriteLine();
switch (char.ToLower(key))
{
case '1':
Configuration.SelectedWireMode = WireMode.Compact;
System.Console.WriteLine("✓ WireMode set to Compact");
return;
case '2':
Configuration.SelectedWireMode = WireMode.Fast;
System.Console.WriteLine("✓ WireMode set to Fast");
return;
case 'b':
return;
default:
continue;
}
}
}
///
/// Prompts the user for an integer with a default (current value). Returns the current value if
/// the user presses Enter on empty input or if parsing fails / value is below the minimum.
///
private static int PromptInt(string name, int currentValue, int min)
{
System.Console.Write($" {name} [{currentValue}]: ");
var input = System.Console.ReadLine()?.Trim() ?? "";
if (input.Length == 0) return currentValue;
if (int.TryParse(input, out var newValue) && newValue >= min) return newValue;
System.Console.WriteLine($" ! Invalid value (need int ≥ {min}) — keeping {currentValue}");
return currentValue;
}
}