Add an ByteBuf -> Buffer adaptor (#11518)

Add an ByteBuf -> Buffer adaptor

Motivation:

For migration of APIs from `ByteBuf` to `Buffer` sometime we may have to bridge APIs which use a `ByteBuf` (eg: `ByteToMessageDecoder` at the moment) to APIs that use a `Buffer` even when the allocator for the `ByteBuf` isn't migrated to use `ByteBufAllocatorAdaptor`.

Modification:

- Add a simple copy adaptor that copies all data from `ByteBuf` to a new `Buffer`.
- I noticed we do not have a `writeBytes` method with offsets, so added that too.

Result:

One more adaptor to bridge old and new buffer APIs.
This commit is contained in:
Nitesh Kant 2021-07-28 02:16:55 -07:00 committed by GitHub
parent 564c8c3f7c
commit 4259db264f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 4 deletions

View File

@ -285,11 +285,23 @@ public interface Buffer extends Resource<Buffer>, BufferAccessor {
* @return This buffer.
*/
default Buffer writeBytes(byte[] source) {
int size = source.length;
return writeBytes(source, 0, source.length);
}
/**
* Writes into this buffer, all the bytes from the given byte array.
* This updates the {@linkplain #writerOffset() write offset} of this buffer by the length of the array.
*
* @param source The byte array to read from.
* @param srcPos Position in the {@code source} from where bytes should be written to this buffer.
* @param length The number of bytes to copy.
* @return This buffer.
*/
default Buffer writeBytes(byte[] source, int srcPos, int length) {
int woff = writerOffset();
writerOffset(woff + size);
for (int i = 0; i < size; i++) {
setByte(woff + i, source[i]);
writerOffset(woff + length);
for (int i = 0; i < length; i++) {
setByte(woff + i, source[srcPos + i]);
}
return this;
}

View File

@ -79,6 +79,29 @@ public final class ByteBufAdaptor extends ByteBuf {
return null;
}
/**
* Extracts the underlying {@link Buffer} instance that is backing this {@link ByteBuf}, if any.
* This is similar to {@link #unwrap()} except the return type is a {@link Buffer}.
* If this {@link ByteBuf} does not wrap a {@link Buffer}, then a new {@code Buffer} instance is returned with the
* contents copied from the given {@link ByteBuf}.
*
* @param byteBuf The {@link ByteBuf} to extract the {@link Buffer} from.
* @return The {@link Buffer} instance that is backing the given {@link ByteBuf}, or a new {@code Buffer}
* containing the contents copied from the given {@link ByteBuf}. If the data is copied, the passed {@link ByteBuf}
* will be {@link ByteBuf#release() released}.
*/
public static Buffer extractOrCopy(BufferAllocator allocator, ByteBuf byteBuf) {
final Buffer extracted = extract(byteBuf);
if (extracted != null) {
return extracted;
}
try {
return allocator.allocate(byteBuf.capacity()).writeBytes(ByteBufUtil.getBytes(byteBuf));
} finally {
byteBuf.release();
}
}
@Override
public int capacity() {
return buffer.capacity();

View File

@ -258,4 +258,17 @@ public class BufferBulkAccessTest extends BufferTestSupport {
assertThat(toByteArray(buffer)).containsExactly(1, 2, 3, 4, 5, 6, 7, 0);
}
}
@ParameterizedTest
@MethodSource("allocators")
public void writeBytesWithOffsetMustWriteAllBytesFromByteArray(Fixture fixture) {
try (BufferAllocator allocator = fixture.createAllocator();
Buffer buffer = allocator.allocate(3)) {
buffer.writeByte((byte) 1);
buffer.writeBytes(new byte[] {2, 3, 4, 5, 6, 7}, 1, 2);
assertThat(buffer.writerOffset()).isEqualTo(3);
assertThat(buffer.readerOffset()).isZero();
assertThat(toByteArray(buffer)).containsExactly(1, 3, 4);
}
}
}