Proposal: Support ref struct buffer writers via allows ref struct constraint (.NET 9+)
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 4.7k
- Forks
- 313
- PR merge metrics
- No merged PRs in 30d
Description
The Problem
Currently, when using MemoryPack with highly optimized, custom memory allocators (like native/unmanaged memory arenas), users are forced to implement IBufferWriter<byte>. The interface requires implementing GetMemory(), which returns a Memory<byte>. Wrapping a raw pointer in a Memory<byte> necessitates allocating a heap-based MemoryManager<T> per buffer.
Since MemoryPackWriter only ever uses GetSpan() and never actually calls GetMemory(), this forces a completely unnecessary heap allocation just to satisfy the interface constraints, which goes against the high-performance, zero-allocation philosophy of MemoryPack.
Proposed Solution
With the introduction of C# 13 and .NET 9, we can utilize the allows ref struct anti-constraint.
By applying this constraint to the TBufferWriter generic parameter in MemoryPackWriter<TBufferWriter> and its related core interfaces (conditionally under #if NET9_0_OR_GREATER), developers could pass ref struct implementations of IBufferWriter<byte>. This would allow custom writers to throw NotSupportedException in GetMemory() and rely purely on GetSpan(), completely avoiding heap allocations for native memory buffers.
Impact and Considerations
- Performance: Unlocks true zero-allocation custom buffer writers for unmanaged memory.
- Backwards Compatibility: We can wrap this in
#if NET9_0_OR_GREATERdirectives so .NET 7 and 8 users are unaffected. - Compiler Limitations: There is a known limitation in C# 13 (CS9050) where a
reffield cannot refer to aref structanti-constraint generic parameter. This would require an internal workaround usingref byteandUnsafe.As. - Breaking Changes (.NET 9 only): This would be a source-breaking change for .NET 9 users who have written custom formatters inheriting from
MemoryPackFormatter<T>, as they would need to propagate theallows ref structconstraint. (The MemoryPack source generator itself implicitly handles constraints via explicit interface implementations).
I have a working implementation for this on a fork and can submit a PR if this proposal is accepted.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing MemoryPackWriter and the related core interfaces, focusing on their IBufferWriter constraints and the NET9_0_OR_GREATER conditionals. Compare the proposed approach with the working fork implementation and account for the C# 13 CS9050 limitation. Done means ref struct writers can rely on GetSpan() without heap allocation while existing .NET 7 and 8 behavior remains unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100