package io.lacuna.bifurcan; import io.lacuna.bifurcan.durable.Encodings; import io.lacuna.bifurcan.durable.allocator.IBuffer; import io.lacuna.bifurcan.durable.io.ByteChannelOutput; import io.lacuna.bifurcan.durable.Util; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; /** * An implementation of {@link DataOutput} with some additional utility functions. */ public interface DurableOutput extends DataOutput, Flushable, Closeable, AutoCloseable { /** * @return an output wrapped around {@code os} */ static DurableOutput from(OutputStream os) { return new ByteChannelOutput(Channels.newChannel(os), 16 << 10); } /** * @return an output wrapped around {@code channel} */ static DurableOutput from(WritableByteChannel channel) { return new ByteChannelOutput(channel, 16 << 10); } default void write(byte[] b) { write(b, 0, b.length); } default void write(byte[] b, int off, int len) { write(ByteBuffer.wrap(b, off, len)); } void close(); /** * Writes an {@code int8} to the output. */ void writeByte(int v); /** * Writes an {@code uint8} to the output. */ default void writeUnsignedByte(int v) { writeByte((byte) (v & 0xFF)); } /** * Writes an {@code int16} to the output. */ void writeShort(int v); /** * Writes an {@code uint16} to the output. */ default void writeUnsignedShort(int v) { writeShort((short) (v & 0xFFFF)); } /** * Writes an {@code int16} to the output. */ void writeChar(int v); /** * Writes an {@code int32} to the output. */ void writeInt(int v); /** * Writes an {@code uint32} to the output. */ default void writeUnsignedInt(long v) { writeInt((int) (v & 0xFFFFFFFFL)); } /** * Writes an {@code int64} to the output. */ void writeLong(long v); /** * Writes a {@code float32} to the output. */ void writeFloat(float v); /** * Writes a {@code float64} to the output. */ void writeDouble(double v); /** * Flushes any buffered data to the underlying sink. */ void flush(); /** * @return the number of bytes written to the output */ long written(); /** * Copies all bytes from {@code src} to the output, returning the number of bytes copied. */ int write(ByteBuffer src); default void writeVLQ(long n) { Encodings.writeVLQ(n, this); } default void writeUVLQ(long n) { Encodings.writeUVLQ(n, this); } default void write(int b) { writeByte(b); } default void writeBytes(String s) { for (int i = 0; i < s.length(); i++) { writeByte(s.charAt(i) & 0xFF); } } default void writeChars(String s) { for (int i = 0; i < s.length(); i++) { writeChar(s.charAt(i)); } } default void writeUTF(String s) { byte[] encoded = s.getBytes(Util.UTF_8); if (encoded.length > 0xFFFF) { throw new IllegalArgumentException("string is too large"); } writeShort(encoded.length); write(encoded); } default void writeBoolean(boolean v) { writeByte((byte) (v ? 0x1 : 0x0)); } /** * Copies all bytes from {@code in} to the output. */ void transferFrom(DurableInput in); /** * Appends {@code buffers} to the output. * * Intended for internal use, may be subject to change. */ void append(Iterable<IBuffer> buffers); /** * @return an {@link OutputStream} corresponding to this output */ default OutputStream asOutputStream() { return new OutputStream() { private final DurableOutput out = DurableOutput.this; @Override public void write(byte[] b, int off, int len) { out.write(b, off, len); } @Override public void flush() { out.flush(); } @Override public void close() { out.close(); } @Override public void write(int b) { out.writeByte(b); } }; } }