using AyCode.Core.Serializers.Binaries; using AyCode.Core.Serializers.Console.Benchmarks; 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(" [1] Latin1FixAscii — empty suffix; short FixStr-fast-path stress (Latin1 baseline values stay short)"); System.Console.WriteLine(" [2] Latin1Short — \" árvíztűrő tükörfúrógép\" (~24 char Hungarian mixed)"); System.Console.WriteLine(" [3] Latin1Long — ~47-char Latin1 mixed (default; exceeds FixStr boundary)"); System.Console.WriteLine(" [4] CjkBmp — CJK BMP (long 3-byte runs)"); System.Console.WriteLine(" [5] Cyrillic — Russian Cyrillic (long 2-byte runs)"); System.Console.WriteLine(" [6] Mixed — Hungarian + CJK + Cyrillic + emoji (full-spectrum + surrogate pairs)"); 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.Latin1Short; System.Console.WriteLine("✓ Charset set to Latin1Short"); return; case '3': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Latin1Long; System.Console.WriteLine("✓ Charset set to Latin1Long"); return; case '4': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.CjkBmp; System.Console.WriteLine("✓ Charset set to CjkBmp"); return; case '5': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Cyrillic; System.Console.WriteLine("✓ Charset set to Cyrillic"); return; case '6': BenchmarkTestDataProvider.LongStringSuffix = CharsetSuffixes.Mixed; System.Console.WriteLine("✓ Charset set to Mixed"); 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; } }