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] AsciiFix — 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] Latin1Fix — 5 char Hungarian (árví) → FixStr-lean tier"); System.Console.WriteLine(" [5] Latin1Short — 40 char Hungarian (árví × 8) → StringSmall tier"); System.Console.WriteLine(" [6] Latin1Long — 280 char Hungarian (default) → StringMedium tier"); System.Console.WriteLine(" [7] CjkBmpShort — 40 char CJK BMP (3-byte runs) → StringSmall tier"); System.Console.WriteLine(" [8] CjkBmpLong — 280 char CJK BMP → StringMedium tier"); System.Console.WriteLine(" [9] CyrillicShort — 40 char Cyrillic (2-byte runs) → StringSmall tier"); System.Console.WriteLine(" [0] CyrillicLong — 280 char Cyrillic → StringMedium tier"); System.Console.WriteLine(" [A] MixedShort — 40 char multi-codepage → StringSmall tier"); System.Console.WriteLine(" [C] 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.AsciiFix; System.Console.WriteLine("✓ Charset set to AsciiFix"); 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.Latin1Fix; System.Console.WriteLine("✓ Charset set to Latin1Fix"); return; case '5': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Short; System.Console.WriteLine("✓ Charset set to Latin1Short"); return; case '6': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Long; System.Console.WriteLine("✓ Charset set to Latin1Long"); return; case '7': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmpShort; System.Console.WriteLine("✓ Charset set to CjkBmpShort"); return; case '8': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmpLong; System.Console.WriteLine("✓ Charset set to CjkBmpLong"); return; case '9': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CyrillicShort; System.Console.WriteLine("✓ Charset set to CyrillicShort"); return; case '0': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CyrillicLong; System.Console.WriteLine("✓ Charset set to CyrillicLong"); return; case 'a': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.MixedShort; System.Console.WriteLine("✓ Charset set to MixedShort"); return; case 'c': 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; } }