Fundamental design issues remain, though.
Drops can end up being shared across instances with different memory allocations, and this means we can't currently attach the de-allocation information to the drop instance.
We also cannot use the AllocationControl instance for this because it has the same problem.
The ability to allocate a buffer on a sub-region of some recoverable memory will be useful when porting over the arena-based pooling allocator from Netty.
Fix a bug in CompositeBuffer.send, where the received buffer would not have ownership.
The fix is to avoid incrementing the reference count in the composite buffer constructor call used in the transferOwnership function.
The state that people really care about is whether or not an Rc has ownership.
Exposing the reference count will probably just confuse people.
The reference count is still exposed on RcSupport because it may be (and is, in the case of ByteBufAdaptor) needed to support implementation details.
These methods make it possible to accurately split composite buffers at component boundaries, either by rounding the offset down or up to the nearest component boundary, respectively.
Composite buffers already support the split method, but it is hard for client code to predict precisely where component boundaries are placed inside composite buffers.
When split is used with an offset that does not land exactly on a component boundary, then the internal component that the offset lands on will also be split.
This may make it harder to precisely reason about memory life cycles and reuse.
This greatly simplifies the semantics around the const buffers.
When they can no longer be made writable, there is no longer any need for "deconstification".
I decided to call the method "makeReadOnly" to distinguish it from "asReadOnly" that is seen in ByteBuf and ByteBuffer. The latter two return read-only _views_ of the buffer, while makeReadOnly changes the state of the buffer in-place.
The const buffers of the various implementations are now able to share the underlying memory.
At least until they are forced not to.
Const buffers will behave ust like normal buffers, except they start out as read-only.
When they are made writable, or sliced, then they will allocate their own independent copy of the memory.
That way, const buffers can have their contents changed, and behave just like normal buffers.
The const-ness is a pure optimisation that should not have any externally observable behaviour.
This abstraction was only used to allow composing over both buffers and sends of buffers, but we can also do that with method overloads.
The Deref had weird semantics and consequences that didn't make much sense.
In other words, it did not pay a return on its complexity cost.
Previously the test results were only attached to passing builds, which is, like, the opposite of useful.
Also finally figured out how to nerf the local docker layer cache.
Recorded this new knowledge as make commands.