Refactored AcBinary to use a single String marker (167) for long-form strings, replacing StringLen8/16/32. Implemented prefix-tier VarUInt encoding for string lengths, introduced FixStrCount constant, and removed legacy LEB128 code paths. Updated all serialization/deserialization logic and documentation to match the new format. Includes related micro-optimizations and code cleanup.
- All serialization APIs now use the declared type (typeof(T) or explicit Type) for dispatch, not value.GetType()
- Added non-generic overloads for Serialize, SerializeChunked, and SerializeChunkedFramed with Type parameter for runtime scenarios
- ScanForDuplicates accepts optional TypeMetadataWrapper to avoid redundant lookups
- Simplified generated writer path and improved wrapper usage
- Benchmarks updated to use new API and cache serialized data
- Minor cleanups: removed unused usings, improved comments, inlined logic
- Ensures consistent, predictable, and more performant type dispatch across all serialization entry points
- Change target framework to net9.0 in AyCode.Core.targets.
- Add DEBUG-only property access diagnostics to AcBinarySerializer for better error reporting.
- Update AcBinaryHubProtocol to dispose chunk state and retry normal parse on unknown bytes, improving resilience after serialization failures.
- Update comments to clarify new logic and rationale.
- Replace single String marker with StringLen8/16/32 (167–169) for explicit string length encoding (1/2/4 bytes)
- Update serialization/deserialization logic and marker checks for new scheme
- Rename charset suffixes: Latin1FixAscii → AsciiFix, add Latin1Fix (5-char Hungarian)
- Update menu, argument parsing, and references for new charset/test names and order
- Swap MaxDepthBehavior enum values: Throw=0, Truncate=1
- Update comments and docs for new marker and charset conventions
Refactored binary string serialization to use a new universal wire format with FixStr (135–166) and String (167) markers and unsigned excess slots, replacing the previous tiered approach. Updated all read/write logic, marker handling, and type code definitions accordingly. FastWire UTF-16 marker (91) now has dedicated handling with legacy compatibility. Removed legacy StringSmall/Medium/Big/Ascii code paths except for backward-compatibility. Improved buffer management in ArrayBinaryOutput and documented new critical issues regarding buffer ownership and disposal. Added new utility methods for marker encoding/decoding and excess slot sizing. Updated documentation and comments to match the new format.
- Refactored string serialization for performance: ASCII-optimistic encode, single pass, and minimal shifting; extracted string interning logic to TryWriteInternedString for both runtime and SGen paths.
- Updated AcBinarySerializer buffer writes to use BufferAt helper, removing redundant bounds checks.
- Enhanced CLI argument parsing to support multiple args and charset selection; unknown args now emit warnings.
- Switched all test data generation from Hungarian to English.
- Benchmark report now includes .NET runtime version.
- Cached MinStringInternLength in AcBinaryDeserializer for performance.
- Minor BinaryTypeCode flag refactor and doc improvements.
- Added BINARY_ISSUES.md entry for FastWire string interning/ref handling desync bug.
- Refactored AcBinaryDeserializer string marker dispatch: hot path now handles all non-interning markers in a single inlinable method, cold path only for interning markers; improved safety and comments.
- Updated SGen codegen to only emit cold-path for interning-enabled types.
- Added debug guard for corrupted wire in ReadStringBig.
- Rewrote JitDisassemblyBenchmark as a direct JIT-disasm harness (outside BDN); updated Program.cs to use it for --jitasm.
- Benchmarks now pin charset to Latin1Short for cross-process consistency.
- Added new Bash commands for diff, JIT disasm, and diagnostics in settings.local.json.
Introduced a new "SGenOnly" build configuration across the solution, updating Directory.Build.props, AyCode.Core.targets, and the .sln file for full support. Centralized TargetFramework and build properties in AyCode.Core.targets, removing redundancy from project files. Updated code to recognize SGEN_ONLY at compile time. Added new Bash commands for file conversion and cleanup. No functional code changes outside build and configuration logic.
- Benchmark charset profiles are now length-consistent: all *Short = 40 chars, all *Long = 280 chars, across ASCII, Latin1, CJK BMP, Cyrillic, and Mixed.
- `CharsetSuffixes` was rewritten with new profiles and base-string repetition for compile-time constants.
- Menu/configuration updated for new profiles, selection logic, and improved descriptions.
- Docs updated to reflect new profiles, lengths, and serialization tier impacts.
- `StringSmall` deserialization split into `ReadStringSmallCompact` and `ReadStringSmallFastWire`; all call sites now dispatch by mode, clarifying the hot path.
- SGen codegen and runtime dispatch tables updated for the new decode split.
- Binary marker docs clarified: only Intern/Metadata/Polymorph features are wire-symmetric for reader case omission; RefHandling is not.
- Added `BINARY_STRICT_SGEN.md` planning doc for a SGen-only, attribute-required, AOT-friendly NuGet package.
Refactored AcBinarySourceGenerator to use RefAwareEmitPredicate for all ref-handling switch decisions, ensuring child property ref-marker logic is based solely on child compile-time flags. Fixed deserialization drift when parent disables ref-handling but child enables it. Added regression tests and new test models to verify correct round-trip behavior for duplicate child references in collections and dictionaries. Improved XML docs and updated conventions for summary tags. Added SGen string round-trip tests for medium UTF-8/ASCII cases.
Refactored string property deserialization to separate hot (common, no-feature) and cold (feature-engaged) marker handling, improving JIT inlining and cold-start performance. Introduced `TryReadStringProperty` (hot, inlined) and `TryReadStringColdPath` (cold, optimized) methods. Updated method attributes for better JIT control and clarified WASM string-cache dead code. Added `BINARY_BYTECODE_OPTIMIZATION.md` and updated related docs. Removed AutoMapper, updated logging package versions, and adjusted project files and settings accordingly.
Added WithProcessStabilization to pin CPU affinity and raise process priority for all BDN entry points, matching Console runner stabilization. Benchmark results are now ordered by Engine then RtPerOp for stable, diff-friendly output. Report headers clarify when BDN manages run parameters. Enhanced comments for clarity; no changes to benchmark logic.
- Introduce BDN-based runner (AcBinaryVsMemPackBenchmark) mirroring Console's FastestByte scenario; add BdnSummaryAdapter for unified result translation.
- Standardize output: both runners emit .log/.LLM/.output triplets; BDN-native artifacts go under Benchmark/BDN/.
- Simplify CLI: replace granular switches with --serializers; update help and usage.
- Remove legacy benchmark classes; focus on scenario-based approach.
- Rewrite README.md for both AyCode.Benchmark and Console to document dual-runner architecture, output conventions, and dependencies.
- Rotate BINARY_TODO.md; archive closed entries to BINARY_TODO_2026_04.md and BINARY_TODO_2026_05.md.
- Add BINARY_SGEN_OPTIMIZATION.md for SGen per-property emit optimization notes.
- Update comments and docstrings for clarity and maintainability; clarify BenchmarkResult iteration semantics for BDN rows.
- Removed Output.cs and migrated all reporting, formatting, and statistics logic to a new BenchmarkReportWriter static class.
- Extended ReportingContext with run-header fields for richer output metadata.
- Updated BenchmarkLoop to use BenchmarkReportWriter and the new ReportingContext.
- Centralized all output file generation (.log, .LLM, .output) and formatting helpers in BenchmarkReportWriter.
- Improved separation of concerns and unified output artifact naming and metadata.
Major refactor: all benchmark engine implementations, enums, and helpers moved from Console project to AyCode.Core.Benchmarks.Workloads.Scenarios for unified cross-runner use. BenchmarkResult and reporting logic moved to AyCode.Core.Benchmarks.Reporting. Attribute-flag aggregation centralized in BenchmarkOptions. Updated all usages, project references, and SGen codegen for ref-handling. Prepares codebase for shared reporting and future extensibility.
Split AcBinarySourceGenerator.cs into multiple partial class files for improved maintainability and clarity. Each major concern (models, type analysis, class info extraction, writer/reader emit, diagnostics, and module init) now resides in its own file. Updated .gitignore and settings.local.json to support the new structure. No functional changes to generator output; this is a pure organizational refactor.
Refactored several methods to use ternary operators and single-line returns for early-exit and exception cases. Improved code readability by condensing multi-line if/else and null checks into concise expressions. No changes to functionality.
Moved StringSmall/Medium/Big/Ascii readers from static helpers in AcBinaryDeserializer to instance methods on BinaryDeserializationContext. Updated all call sites (runtime, SGen, type reader table) to use the new methods. Improved documentation, clarified wire format handling, and added a corrupted-wire guard for StringBig. Removes duplication and centralizes string wire-decode logic.
- Moved interned string decode logic to BinaryDeserializationContext instance methods, reducing duplication and unifying SGen, runtime, and cross-type paths.
- Updated SGen-emitted code and TypeReaderTable to use new context methods.
- Added performance TODO (ACCORE-BIN-T-K9M3) documenting rationale and acceptance.
- Clarified AcBinarySerializableAttribute XML docs.
- Added repo-scoped nuget.config for deterministic restore.
- Updated settings.local.json with new Bash/dev commands.
- Minor code and comment cleanups for clarity.
Add per-type EnablePolymorphDetectFeature flag
Replaces the global UsePolymorphType constant with a per-type EnablePolymorphDetectFeature flag on AcBinarySerializableAttribute. The source generator now emits or omits polymorphic type info for System.Object properties based on this flag, defaulting to enabled. Updates diagnostics, documentation, and SerializableClassInfo to support this feature, clarifying the risks of disabling it and improving attribute XML docs for all feature flags.
Rename ShallowCopy to FlatCopy, add polymorph support
- Renamed all "ShallowCopy" serializer presets and references to "FlatCopy" for clarity and consistency.
- Expanded documentation to clarify flat serialization use cases, especially for delta-update and partial-write scenarios.
- Added EnablePolymorphDetectFeature to AcBinarySerializableAttribute and updated all constructor overloads.
- Set UsePolymorphType = true in AcBinarySourceGenerator to enable polymorphic type support by default.
- Updated all [AcBinarySerializable(...)] usages to include new feature flags, explicitly disabling property filter and polymorph detection for affected types.
- Improved comments and documentation for maintainability.
Add compile-time error for object-typed props w/o polymorph
Introduces ACBIN002: a compile-time diagnostic that errors if a [AcBinarySerializable] type declares a System.Object property while UsePolymorphType is false. This prevents silent wire corruption by requiring the developer to either enable polymorphic serialization, use a concrete type, or ignore the property. The check is integrated into the source generator initialization.
- Introduce `MaxDepthBehavior` option (`Throw`, `Truncate`, `Disable`) for explicit depth-limit handling in AcBinarySerializer and SGen.
- Default is now `Throw` (fail-fast); `ShallowCopy` preset uses `Truncate` for shallow-copy semantics.
- Refactor runtime and SGen paths to use unified `TryEnterRecursion`/`ExitRecursion` for correct wire output and inc/dec symmetry.
- Add focused tests to diagnose SGen+Truncate wire-misalignment bug (see `BINARY_ISSUES.md#accore-bin-i-t7k3`).
- Update docs and comments to clarify new behavior and document Toon serializer's current lack of `MaxDepthBehavior` support.
- Adjust tests and usages for new semantics and improved safety.
Introduced MaxDepthBehavior enum and option to control recursion depth handling (Truncate, Throw, Disable) in AcSerializerOptions. Refactored depth-check logic to use a precomputed NeedsDepthCheck flag. Enhanced exception messages for depth-limit violations. Updated tests to assert correct exception behavior for cycles. Improved documentation and added new test/log commands in settings.local.json.
Refactored AcBinary, AcJson, and AcToon serializers to eliminate the explicit depth parameter from all serialization/deserialization methods, generated code, and interfaces. Introduced a global RecursionDepth field on the serialization context, incremented/decremented at recursion entry/exit, and enforced against MaxDepth as a safety net (except when ReferenceHandling=All). Updated all usages, including property, array, and dictionary handling, to use the new context-based depth tracking. Ensured consistency across runtime and generated code.
Refactored WriteByte, WriteVarUInt, and WriteVarULong to use a new GrowOne helper for single-byte buffer growth. This moves the Output.Grow call out of the hot path, improving inlining and serialization performance for frequent single-byte writes. Added detailed comments explaining the rationale and AOT benefits.
The "Test Type" (TypeName) field was removed from all benchmark output locations, including console summaries, formatted output, and markdown result files. No functional changes were made to the test model definitions; only a BOM was added to SharedTestOrderModels.cs. All other benchmark summary details remain unchanged.
Refactored the benchmark and test data infrastructure to use generic, type-safe, and multi-variant models. Introduced generic base classes for the test data hierarchy and factories, with closing-generic aliases for _All_True and _All_False families. Benchmarks now select the correct test data variant per serializer options, and all serializers are generic over the order type. Output and result reporting now include the CLR type name for clarity. Centralized string property handling and improved documentation throughout.
Refactor tests to use _All_True model types throughout
Replaced all usages of legacy test model types (e.g., TestOrder, TestOrderItem, SharedTag, etc.) with new, feature-complete _All_True variants across SignalR test infrastructure, data sources, and service handlers. Updated all generic constraints, method signatures, and test data to use the new types. Added SharedTestBaseModels.cs and SharedTestOrderModels.cs to define abstract bases and concrete _All_True models with full serialization attributes. This enables more thorough and realistic serialization/deserialization testing and future extensibility.
Refactor benchmark suite to use enums for config
Replaced string parameters for layer, opMode, and serializerMode with strongly-typed enums (BenchmarkLayer, BenchmarkOpMode, SerializerSelectionMode) across BenchmarkLoop, Menu, and Program. Updated CLI parsing and menu logic to use Enum.TryParse and return enums. Added XML docs for new enums. Improves type safety, code clarity, and maintainability.
Refactor benchmarks to use typed enums for engine/mode
Replaced string-based identifiers for serializer engine, I/O mode, and dispatch mode with strongly-typed enums (BenchmarkEngine, BenchmarkIoMode, BenchmarkDispatchMode). Added BenchmarkEnums.cs with ToDisplay() helpers for consistent output. Updated all benchmark implementations, DTOs, and output logic to use enums. Removed obsolete string constants from Configuration.cs. Merged allocation measurement methods in BenchmarkLoop.cs for clarity. Improves type safety, maintainability, and output consistency.
Refactor: move benchmark logic to BenchmarkLoop.cs
Moved all benchmark execution logic (RunBenchmark, RunBenchmarksForTestData, CreateSerializers) from Program.cs into a new static class BenchmarkLoop in BenchmarkLoop.cs. Program.cs now delegates benchmark runs to BenchmarkLoop, improving separation of concerns. No changes to benchmark functionality.
Moved all ISerializerBenchmark implementations for AcBinary and MemoryPack from Program.cs into dedicated files under Benchmarks/. Improves code organization and maintainability; no logic changes, only file structure refactor.
Refactor: extract serializer benchmarks to separate files
Moved AcBinary, MemoryPack, MessagePack, and SystemTextJson benchmark classes into dedicated files for clarity. Centralized options formatting and MemoryPack selection logic in a new BenchmarkOptions helper. Updated Program.cs to use these helpers and removed redundant inline implementations, improving code organization without changing benchmark logic.
Extract ISerializerBenchmark to its own file
Moved ISerializerBenchmark from Program.cs to a new ISerializerBenchmark.cs file under the AyCode.Core.Serializers.Console.Benchmarks namespace. Updated all benchmark classes in Program.cs to implement the interface from the new namespace and made them internal. Added the necessary using directive to Program.cs. Adjusted a PowerShell script in settings.local.json to ensure the new using is present. Removed the old interface definition from Program.cs.
Refactor: move benchmark loop logic to BenchmarkLoop.cs
Refactored all benchmark execution infrastructure from Program.cs into a new internal static class BenchmarkLoop. This includes timing, allocation measurement, progress reporting, GC helpers, MemoryPack setup validation, and test data filtering. Updated Program.cs and all serializer benchmarks to use the new class. Added serAllocPct reporting in Output.cs and a PowerShell script for automated refactoring. No functional changes to benchmark logic.
Refactor: split Program.cs into Menu, Output, DTO
Refactored the benchmark console app for modularity:
- Moved all menu logic to Menu.cs (main/settings menus)
- Moved all output/result formatting to Output.cs
- Extracted BenchmarkResult DTO to BenchmarkResult.cs
- Program.cs now only handles orchestration and the benchmark loop
- Moved GetCurrentCharsetName to Configuration.cs
- Removed obsolete Warmup methods from serializers
No functional changes; improves clarity and maintainability.
Refactor: centralize config/state in Configuration.cs
Moved all benchmark configuration, mutable state, and attribute-flag aggregation from Program.cs to a new Configuration.cs static class. Updated all references in Program.cs and related benchmark classes to use Configuration.<value>. Removed the "profiler" CLI mode and its code. Updated README.md to reflect these changes. This improves maintainability and keeps Program.cs focused on orchestration and UX, with no changes to benchmark logic.
Refactor output, allocation, and summary logic in Program
- Switched if/else and range checks to C# switch expressions for clarity.
- Improved console progress display with cleaner line updates.
- Added Thread.Sleep after JIT pre-warmup for stable benchmarking.
- Enhanced allocation measurement for serializer/deserializer setup.
- Made options and summary output conditional and more consistent.
- Standardized string outputs and comparison headers.
- Improved comments, XML docs, and code style for maintainability.
- No changes to core algorithms; all changes are quality-of-life and output improvements.
Phase-isolated Ser/Des warmup & GC in benchmarks
Refactored benchmark loop to perform separate warmup and measurement for serialization and deserialization phases, with forced GC.Collect at each phase boundary for heap and cache isolation. Added ForceGcCollect() and new WarmupSerialize/WarmupDeserialize interface methods (with defaults). Updated output, documentation, and per-phase iteration handling for improved accuracy and clarity. Added detailed comments explaining rationale and effects.
AcBinary: add framing doc, buffer growth fixes, doc updates
- Added `BINARY_WHYUSE.md` for architectural framing and value proposition
- Updated `BINARY_FEATURES.md` and `README.md` to reference and prioritize the new doc
- Documented AsyncPipeWriterOutput chunk-size limitation and workarounds in `BINARY_ASYNCPIPE_ISSUES.md`
- Refactored buffer growth logic in `AcBinarySerializer.BinarySerializationContext.cs` to validate capacity after grow and throw clear exceptions on under-provisioning; removed dead method
- Fixed chunk size alignment bug in `AsyncPipeWriterOutput.cs` to prevent buffer under-provisioning
- Added `AYCODE_NATIVEAOT` build config support in `Program.cs`
- Improved documentation clarity and error diagnostics for streaming/buffered serialization edge cases
Enable per-type property filter opt-out in AcBinary
Adds EnablePropertyFilterFeature to AcBinarySerializableAttribute, allowing types to opt out of property filter codegen and runtime checks. Updates source generator, metadata, and runtime logic to honor this flag. Removes UsePropertyFilter constant; emission is now attribute-driven. Also optimizes string serialization for non-ASCII cases and refactors deserializer byte reads for trusted single-segment fast paths. Backward compatible: property filter remains enabled by default.
Optimize AcBinary: add IsTrustedSingleSegment fast-path
Introduce static abstract IsTrustedSingleSegment to IBinaryInputBase and implement in all input types. Update EnsureAvailable to leverage JIT specialization for array-backed inputs, eliminating per-read overhead. Add detailed XML docs on performance trade-offs. No breaking changes; improves deserialization efficiency and clarity.
FastWire: Add markerless string encoding/decoding
Introduced a markerless FastWire path for string properties and collection elements in AcBinary serialization. Strings are now encoded with a 4-byte int32 sentinel header (-1=null, 0=empty, N>0=content) and UTF-16 bytes, eliminating the type code marker in FastWire mode. Updated code generation, runtime, and documentation to support this, while preserving Compact mode behavior and cross-mode compatibility.
Use ReadOnlySequence<byte> in benchmarks for deserialization
Updated all AcBinary and MemoryPack benchmark deserialization and round-trip verification methods to use ReadOnlySequence<byte> overloads instead of byte[] or ToArray(). This ensures benchmarks exercise the production-realistic deserialization path (e.g., for SignalR/Pipe consumers) and aligns buffer writer semantics across serializers. Added comments to clarify intent. No business logic was changed.
Switch to BCL UTF-8 APIs for string (de)serialization
Replaced custom Utf8Transcoder logic with System.Text.Encoding.UTF8 and System.Text.Unicode.Utf8 for string encoding/decoding in AcBinarySerializer and AcBinaryDeserializer. PropertyMetadataBase now uses Encoding.UTF8.GetBytes for property name encoding. Retained Utf8Transcoder for any remaining SIMD/custom logic. No public API changes; internal refactoring for performance and maintainability.
Benchmark stabilization & charset-param workload support
Major overhaul of the custom benchmark harness:
- Per-serializer warmup, GC isolation, pilot discard, and CPU pinning for stable, reproducible results
- Adaptive per-cell iteration targeting (~250ms/sample) and statistical reporting (min/max/stddev/CV)
- CLI/menu support for single-cell A/B runs
- Test data refactored to ASCII baselines with configurable charset suffix (6 presets), selectable via menu; charset recorded in all outputs
- Markdown/console output now includes per-op µs, inter-sample range, CV warnings, and iteration counts
- Documentation updated with rationale, methodology, and notes on reverted/experimental optimizations
Enables reliable, cross-charset, release-grade performance measurement for AcBinary.