Follow-up from PR #51.
Current behavior
In the generated merge_field arm for a bytes_fields-tagged field:
self.value = ::bytes::Bytes::from(::buffa::types::decode_bytes(buf)?);
decode_bytes allocates a Vec<u8>, set_lens it, and copy_to_slices into it. Then Bytes::from(Vec<u8>) wraps without a second copy. Net: one allocation + one memcpy per field.
What we'd want
Buf::copy_to_bytes(len) is the Buf trait's native "take N bytes as Bytes" call. For a Bytes-backed Buf, the default impl calls Bytes::split_to(len) which is zero-copy (just a refcount bump + length adjustment). For &[u8]-backed Buf, the default falls back to an allocation+copy — same as today.
So on hot paths where the decoder is already reading from a Bytes buffer, the bytes field ends up aliasing the input buffer with no copy.
Proposal
Add a decode_bytes_to_bytes<B: Buf>(buf: &mut B) -> Result<Bytes> (or make decode_bytes generic over its output type) that calls buf.copy_to_bytes(len) instead of allocating a Vec. Codegen for bytes_fields arms switches to the new function.
Ensure:
Follow-up from PR #51.
Current behavior
In the generated
merge_fieldarm for abytes_fields-tagged field:decode_bytesallocates aVec<u8>,set_lens it, andcopy_to_slices into it. ThenBytes::from(Vec<u8>)wraps without a second copy. Net: one allocation + one memcpy per field.What we'd want
Buf::copy_to_bytes(len)is theBuftrait's native "take N bytes asBytes" call. For aBytes-backedBuf, the default impl callsBytes::split_to(len)which is zero-copy (just a refcount bump + length adjustment). For&[u8]-backedBuf, the default falls back to an allocation+copy — same as today.So on hot paths where the decoder is already reading from a
Bytesbuffer, the bytes field ends up aliasing the input buffer with no copy.Proposal
Add a
decode_bytes_to_bytes<B: Buf>(buf: &mut B) -> Result<Bytes>(or makedecode_bytesgeneric over its output type) that callsbuf.copy_to_bytes(len)instead of allocating aVec. Codegen forbytes_fieldsarms switches to the new function.Ensure:
merge_field(owned) and, once AnyView::to_owned_message copies Bytes payload unnecessarily #52 is done, view decode.copy_to_bytes(the currentdecode_bytesvalidates againstbuf.remaining()already — preserve that).no_stdcompat unchanged.