ByteBuffer
is a longstanding problem in several of our codebases, because we need to pass the type everywhere (in order to avoid allocating and copying to [UInt8]
) and this implies that SwiftNIO must become a universal dependency, even in components that have nothing to do with networking. therefore we’ve been working hard to remove ByteBuffer
from as many places in our code as possible, and replacing it with a standard [UInt8]
storage.
one obstacle we have run into during this refactor is ByteToMessageDecoder
. the wire protocol logic looks a bit like:
extension SomeWireMessageDecoder:ByteToMessageDecoder
{
public mutating
func decode(context:ChannelHandlerContext, buffer:inout ByteBuffer) throws -> DecodingState
{
let header:MessageHeader
if let seen:MessageHeader = self.header
{
header = seen
}
else if MessageHeader.size <= buffer.readableBytes
{
header = try .parse(from: &buffer)
}
else
{
return .needMoreData
}
guard header.count <= buffer.readableBytes
else
{
self.header = header
return .needMoreData
}
self.header = nil
let message:MessageBody<ByteBufferView> = try .parse(from: &buffer,
length: header.count)
context.fireChannelRead(self.wrapInboundOut(message))
return .continue
}
}
this code relies on SwiftNIO to accumulate the raw data into a ByteBuffer
instead of a [UInt8]
, which i understand is sometimes desirable because ByteBuffer
can reallocate in-place while [UInt8]
always needs a new allocation on resize. but in this case, we already know the length of the expected message from reading the header, and we are just wrapping a view of the buffer in a MessageBody<some RandomAccessCollection>
, so ByteBuffer
doesn’t provide any benefits over [UInt8]
.
how difficult would it be to create an analogue to ByteToMessageDecoder
that accumulates into a [UInt8]
with a size hint instead of ByteBuffer
?