I made a post in "Using Swift" which is related to this thread:
Correction: the encoder is 40% faster ;)
In short, the Encoder type is the configuration. Due to this, the compiler obtains more optimisation opportunities. The implementation uses conforming types to Encodable as usual, its strategies are reusable and composable, it's clean and maintainable code - and has no hacks, no unsafe code.
This pattern can be applied to decoders as well.
Quick Insights
Core Architecture
- StaticJSONEncoder with compile-time configuration via generic parameters
- Protocol-based strategies using associated types (no runtime dispatch)
- Reusable state and sink design for zero-allocation hot loops
- JSONDataSink optimized for UTF-8 and minimal copies
Performance Achievements *)
Foundation: 359ms, 5469M instructions, 2000K allocations
StaticEncoder: 212ms, 3165M instructions, 1200K allocations
With reuse **) : 192ms, 2816M instructions, 800K allocations
→ 41% faster (47% with reuse)
→ 42% fewer instructions
→ 40% fewer allocations
*) 100_000 encoding passes for a simple composite (nested) struct
**) Sink, which can be cleared, and Encoder State - which will always be cleared.
The state is still a class - unfortunately, it can't be avoided that easily.