Last active
June 28, 2022 03:50
-
-
Save bnorm/34fffd47169fd561eb522910a655a8a7 to your computer and use it in GitHub Desktop.
Okio Source/Sink for ByteBuffers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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