Skip to content

Instantly share code, notes, and snippets.

@bnorm
Last active June 28, 2022 03:50
Show Gist options
  • Save bnorm/34fffd47169fd561eb522910a655a8a7 to your computer and use it in GitHub Desktop.
Save bnorm/34fffd47169fd561eb522910a655a8a7 to your computer and use it in GitHub Desktop.
Okio Source/Sink for ByteBuffers
import java.io.IOException;
import java.nio.ByteBuffer;
import okio.Buffer;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
import okio.Sink;
import okio.Source;
import okio.Timeout;
public final class ByteBuffers {
private void run() throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(128);
BufferedSink sink = Okio.buffer(new ByteBufferSink(buffer));
sink.writeUtf8("Hello, ByteBuffers!");
sink.close();
buffer.limit(19);
buffer.position(7);
BufferedSource source = Okio.buffer(new ByteBufferSource(buffer));
System.out.println(source.readUtf8());
source.close();
}
static final class ByteBufferSource implements Source {
final ByteBuffer buffer;
final Buffer.UnsafeCursor cursor = new Buffer.UnsafeCursor();
ByteBufferSource(ByteBuffer buffer) {
this.buffer = buffer.asReadOnlyBuffer(); // Maintain separate position
}
@Override
public long read(Buffer sink, long byteCount) {
if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
if (byteCount == 0) return 0;
if (buffer.remaining() == 0) return -1;
byteCount = (int) Math.min(byteCount, buffer.remaining());
int remaining = (int) byteCount;
sink.readAndWriteUnsafe(cursor);
try {
cursor.seek(sink.size());
cursor.resizeBuffer(sink.size() + byteCount);
while (remaining > 0) {
int toRead = Math.min(remaining, cursor.end - cursor.start);
buffer.get(cursor.data, cursor.start, toRead);
remaining -= toRead;
cursor.next();
}
} finally {
// Truncate sink to the data that was actually written
cursor.resizeBuffer(sink.size() - remaining);
cursor.close();
}
return byteCount;
}
@Override
public Timeout timeout() {
return Timeout.NONE;
}
@Override
public void close() {
}
}
static final class ByteBufferSink implements Sink {
final ByteBuffer buffer;
final Buffer.UnsafeCursor cursor = new Buffer.UnsafeCursor();
ByteBufferSink(ByteBuffer buffer) {
this.buffer = buffer.duplicate(); // Maintain separate position
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
if (byteCount == 0) return;
if (byteCount + buffer.position() > buffer.limit())
throw new IOException(String.format("overflow: byteCount=%d position=%d limit=%d",
byteCount, buffer.position(), buffer.limit()));
source.readUnsafe(cursor);
try {
long remaining = byteCount;
while (remaining > 0) {
cursor.next();
int toWrite = (int) Math.min(remaining, cursor.end - cursor.start);
buffer.put(cursor.data, cursor.start, toWrite);
remaining -= toWrite;
}
} finally {
cursor.close();
}
}
@Override
public void flush() {
}
@Override
public Timeout timeout() {
return Timeout.NONE;
}
@Override
public void close() {
}
}
public static void main(String... args) throws Exception {
new ByteBuffers().run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment