Simplified the serialisation format. Other task #39.

The new format is simpler but less efficient for small integers, short
strings and short byte arrays.
This commit is contained in:
akwizgran
2014-01-14 22:40:47 +00:00
parent 8886d954d7
commit db96994d5c
15 changed files with 314 additions and 680 deletions

View File

@@ -218,13 +218,13 @@ abstract class Connector extends Thread {
}
protected void sendTimestamp(Writer w, long timestamp) throws IOException {
w.writeInt64(timestamp);
w.writeInteger(timestamp);
w.flush();
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent timestamp");
}
protected long receiveTimestamp(Reader r) throws IOException {
long timestamp = r.readInt64();
long timestamp = r.readInteger();
if(timestamp < 0) throw new FormatException();
if(LOG.isLoggable(INFO)) LOG.info(pluginName + " received timestamp");
return timestamp;

View File

@@ -94,7 +94,7 @@ class MessageFactoryImpl implements MessageFactory {
if(author == null) w.writeNull();
else writeAuthor(w, author);
w.writeString(contentType);
w.writeIntAny(timestamp);
w.writeInteger(timestamp);
byte[] salt = new byte[MESSAGE_SALT_LENGTH];
random.nextBytes(salt);
w.writeBytes(salt);

View File

@@ -56,7 +56,7 @@ class MessageReader implements StructReader<UnverifiedMessage> {
// Read the content type
String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
// Read the timestamp
long timestamp = r.readIntAny();
long timestamp = r.readInteger();
if(timestamp < 0) throw new FormatException();
// Read the salt
byte[] salt = r.readBytes(MESSAGE_SALT_LENGTH);

View File

@@ -165,7 +165,7 @@ class PacketReaderImpl implements PacketReader {
public RetentionAck readRetentionAck() throws IOException {
r.readStructStart(RETENTION_ACK);
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
r.readStructEnd();
return new RetentionAck(version);
@@ -177,9 +177,9 @@ class PacketReaderImpl implements PacketReader {
public RetentionUpdate readRetentionUpdate() throws IOException {
r.readStructStart(RETENTION_UPDATE);
long retention = r.readIntAny();
long retention = r.readInteger();
if(retention < 0) throw new FormatException();
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
r.readStructEnd();
return new RetentionUpdate(retention, version);
@@ -191,7 +191,7 @@ class PacketReaderImpl implements PacketReader {
public SubscriptionAck readSubscriptionAck() throws IOException {
r.readStructStart(SUBSCRIPTION_ACK);
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
r.readStructEnd();
return new SubscriptionAck(version);
@@ -213,7 +213,7 @@ class PacketReaderImpl implements PacketReader {
r.readStructStart(TRANSPORT_ACK);
byte[] b = r.readBytes(UniqueId.LENGTH);
if(b.length < UniqueId.LENGTH) throw new FormatException();
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
r.readStructEnd();
return new TransportAck(new TransportId(b), version);
@@ -245,7 +245,7 @@ class PacketReaderImpl implements PacketReader {
}
r.readMapEnd();
// Read the version number
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
// Read the end of the struct
r.readStructEnd();

View File

@@ -101,22 +101,22 @@ class PacketWriterImpl implements PacketWriter {
public void writeRetentionAck(RetentionAck a) throws IOException {
w.writeStructStart(RETENTION_ACK);
w.writeIntAny(a.getVersion());
w.writeInteger(a.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}
public void writeRetentionUpdate(RetentionUpdate u) throws IOException {
w.writeStructStart(RETENTION_UPDATE);
w.writeIntAny(u.getRetentionTime());
w.writeIntAny(u.getVersion());
w.writeInteger(u.getRetentionTime());
w.writeInteger(u.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}
public void writeSubscriptionAck(SubscriptionAck a) throws IOException {
w.writeStructStart(SUBSCRIPTION_ACK);
w.writeIntAny(a.getVersion());
w.writeInteger(a.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}
@@ -132,7 +132,7 @@ class PacketWriterImpl implements PacketWriter {
w.writeStructEnd();
}
w.writeListEnd();
w.writeIntAny(u.getVersion());
w.writeInteger(u.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}
@@ -140,7 +140,7 @@ class PacketWriterImpl implements PacketWriter {
public void writeTransportAck(TransportAck a) throws IOException {
w.writeStructStart(TRANSPORT_ACK);
w.writeBytes(a.getId().getBytes());
w.writeIntAny(a.getVersion());
w.writeInteger(a.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}
@@ -149,7 +149,7 @@ class PacketWriterImpl implements PacketWriter {
w.writeStructStart(TRANSPORT_UPDATE);
w.writeBytes(u.getId().getBytes());
w.writeMap(u.getProperties());
w.writeIntAny(u.getVersion());
w.writeInteger(u.getVersion());
w.writeStructEnd();
if(flush) out.flush();
}

View File

@@ -38,7 +38,7 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> {
groups.add(groupReader.readStruct(r));
r.readListEnd();
// Read the version number
long version = r.readIntAny();
long version = r.readInteger();
if(version < 0) throw new FormatException();
// Read the end of the struct
r.readStructEnd();

View File

@@ -1,5 +1,17 @@
package org.briarproject.serial;
import static org.briarproject.serial.Tag.BYTES;
import static org.briarproject.serial.Tag.END;
import static org.briarproject.serial.Tag.FALSE;
import static org.briarproject.serial.Tag.FLOAT;
import static org.briarproject.serial.Tag.INTEGER;
import static org.briarproject.serial.Tag.LIST;
import static org.briarproject.serial.Tag.MAP;
import static org.briarproject.serial.Tag.NULL;
import static org.briarproject.serial.Tag.STRING;
import static org.briarproject.serial.Tag.STRUCT;
import static org.briarproject.serial.Tag.TRUE;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -25,15 +37,9 @@ class ReaderImpl implements Reader {
this.in = in;
}
public boolean eof() throws IOException {
if(!hasLookahead) readLookahead();
return eof;
}
private void readLookahead() throws IOException {
assert !eof;
// If one or two lookahead bytes have been read, feed the consumers
if(hasLookahead) consumeLookahead();
assert !hasLookahead;
// Read a lookahead byte
int i = in.read();
if(i == -1) {
@@ -42,7 +48,7 @@ class ReaderImpl implements Reader {
}
next = (byte) i;
// If necessary, read another lookahead byte
if(next == Tag.STRUCT) {
if(next == STRUCT) {
i = in.read();
if(i == -1) throw new FormatException();
nextStructId = (byte) i;
@@ -54,11 +60,68 @@ class ReaderImpl implements Reader {
assert hasLookahead;
for(Consumer c : consumers) {
c.write(next);
if(next == Tag.STRUCT) c.write(nextStructId);
if(next == STRUCT) c.write(nextStructId);
}
hasLookahead = false;
}
private void readIntoBuffer(byte[] b, int length, boolean consume)
throws IOException {
int offset = 0;
while(offset < length) {
int read = in.read(b, offset, length - offset);
if(read == -1) throw new FormatException();
offset += read;
}
if(consume) for(Consumer c : consumers) c.write(b, 0, length);
}
private void readIntoBuffer(int length, boolean consume)
throws IOException {
if(buf.length < length) buf = new byte[length];
readIntoBuffer(buf, length, consume);
}
private int readInt32(boolean consume) throws IOException {
readIntoBuffer(4, consume);
int value = 0;
for(int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
return value;
}
private long readInt64(boolean consume) throws IOException {
readIntoBuffer(8, consume);
long value = 0;
for(int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
return value;
}
private void skip(int length) throws IOException {
while(length > 0) {
int read = in.read(buf, 0, Math.min(length, buf.length));
if(read == -1) throw new FormatException();
length -= read;
}
}
private void skipObject() throws IOException {
if(hasBoolean()) skipBoolean();
else if(hasInteger()) skipInteger();
else if(hasFloat()) skipFloat();
else if(hasString()) skipString(Integer.MAX_VALUE);
else if(hasBytes()) skipBytes(Integer.MAX_VALUE);
else if(hasList()) skipList();
else if(hasMap()) skipMap();
else if(hasStruct()) skipStruct();
else if(hasNull()) skipNull();
else throw new FormatException();
}
public boolean eof() throws IOException {
if(!hasLookahead) readLookahead();
return eof;
}
public void close() throws IOException {
in.close();
}
@@ -74,13 +137,13 @@ class ReaderImpl implements Reader {
public boolean hasBoolean() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.FALSE || next == Tag.TRUE;
return next == FALSE || next == TRUE;
}
public boolean readBoolean() throws IOException {
if(!hasBoolean()) throw new FormatException();
consumeLookahead();
return next == Tag.TRUE;
return next == TRUE;
}
public void skipBoolean() throws IOException {
@@ -88,289 +151,95 @@ class ReaderImpl implements Reader {
hasLookahead = false;
}
public boolean hasUint7() throws IOException {
public boolean hasInteger() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next >= 0;
return next == INTEGER;
}
public byte readUint7() throws IOException {
if(!hasUint7()) throw new FormatException();
public long readInteger() throws IOException {
if(!hasInteger()) throw new FormatException();
consumeLookahead();
return next;
return readInt64(true);
}
public void skipUint7() throws IOException {
if(!hasUint7()) throw new FormatException();
hasLookahead = false;
}
public boolean hasInt8() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.INT8;
}
public byte readInt8() throws IOException {
if(!hasInt8()) throw new FormatException();
consumeLookahead();
int i = in.read();
if(i == -1) {
eof = true;
throw new FormatException();
}
byte b = (byte) i;
// Feed the hungry mouths
for(Consumer c : consumers) c.write(b);
return b;
}
public void skipInt8() throws IOException {
if(!hasInt8()) throw new FormatException();
if(in.read() == -1) {
eof = true;
throw new FormatException();
}
hasLookahead = false;
}
public boolean hasInt16() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.INT16;
}
public short readInt16() throws IOException {
if(!hasInt16()) throw new FormatException();
consumeLookahead();
readIntoBuffer(2);
return (short) (((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF));
}
private void readIntoBuffer(int length) throws IOException {
if(buf.length < length) buf = new byte[length];
readIntoBuffer(buf, length);
}
private void readIntoBuffer(byte[] b, int length) throws IOException {
assert !hasLookahead;
int offset = 0;
while(offset < length) {
int read = in.read(b, offset, length - offset);
if(read == -1) {
eof = true;
throw new FormatException();
}
offset += read;
}
// Feed the hungry mouths
for(Consumer c : consumers) c.write(b, 0, length);
}
public void skipInt16() throws IOException {
if(!hasInt16()) throw new FormatException();
hasLookahead = false;
skip(2);
}
private void skip(int length) throws IOException {
while(length > 0) {
int read = in.read(buf, 0, Math.min(length, buf.length));
if(read == -1) {
eof = true;
throw new FormatException();
}
length -= read;
}
}
public boolean hasInt32() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.INT32;
}
public int readInt32() throws IOException {
if(!hasInt32()) throw new FormatException();
consumeLookahead();
return readInt32Bits();
}
private int readInt32Bits() throws IOException {
readIntoBuffer(4);
return ((buf[0] & 0xFF) << 24) | ((buf[1] & 0xFF) << 16) |
((buf[2] & 0xFF) << 8) | (buf[3] & 0xFF);
}
public void skipInt32() throws IOException {
if(!hasInt32()) throw new FormatException();
hasLookahead = false;
skip(4);
}
public boolean hasInt64() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.INT64;
}
public long readInt64() throws IOException {
if(!hasInt64()) throw new FormatException();
consumeLookahead();
return readInt64Bits();
}
private long readInt64Bits() throws IOException {
readIntoBuffer(8);
return ((buf[0] & 0xFFL) << 56) | ((buf[1] & 0xFFL) << 48) |
((buf[2] & 0xFFL) << 40) | ((buf[3] & 0xFFL) << 32) |
((buf[4] & 0xFFL) << 24) | ((buf[5] & 0xFFL) << 16) |
((buf[6] & 0xFFL) << 8) | (buf[7] & 0xFFL);
}
public void skipInt64() throws IOException {
if(!hasInt64()) throw new FormatException();
hasLookahead = false;
public void skipInteger() throws IOException {
if(!hasInteger()) throw new FormatException();
skip(8);
}
public boolean hasIntAny() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next >= 0 || next == Tag.INT8 || next == Tag.INT16
|| next == Tag.INT32 || next == Tag.INT64;
}
public long readIntAny() throws IOException {
if(!hasIntAny()) throw new FormatException();
if(next >= 0) return readUint7();
if(next == Tag.INT8) return readInt8();
if(next == Tag.INT16) return readInt16();
if(next == Tag.INT32) return readInt32();
if(next == Tag.INT64) return readInt64();
throw new IllegalStateException();
}
public void skipIntAny() throws IOException {
if(!hasIntAny()) throw new FormatException();
if(next >= 0) skipUint7();
else if(next == Tag.INT8) skipInt8();
else if(next == Tag.INT16) skipInt16();
else if(next == Tag.INT32) skipInt32();
else if(next == Tag.INT64) skipInt64();
else throw new IllegalStateException();
}
public boolean hasFloat32() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.FLOAT32;
}
public float readFloat32() throws IOException {
if(!hasFloat32()) throw new FormatException();
consumeLookahead();
return Float.intBitsToFloat(readInt32Bits());
}
public void skipFloat32() throws IOException {
if(!hasFloat32()) throw new FormatException();
hasLookahead = false;
skip(4);
}
public boolean hasFloat64() throws IOException {
public boolean hasFloat() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.FLOAT64;
return next == FLOAT;
}
public double readFloat64() throws IOException {
if(!hasFloat64()) throw new FormatException();
public double readFloat() throws IOException {
if(!hasFloat()) throw new FormatException();
consumeLookahead();
return Double.longBitsToDouble(readInt64Bits());
return Double.longBitsToDouble(readInt64(true));
}
public void skipFloat64() throws IOException {
if(!hasFloat64()) throw new FormatException();
hasLookahead = false;
public void skipFloat() throws IOException {
if(!hasFloat()) throw new FormatException();
skip(8);
hasLookahead = false;
}
public boolean hasString() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.STRING;
return next == STRING;
}
public String readString(int maxLength) throws IOException {
if(!hasString()) throw new FormatException();
consumeLookahead();
int length = readLength();
if(length > maxLength) throw new FormatException();
int length = readInt32(true);
if(length < 0 || length > maxLength) throw new FormatException();
if(length == 0) return "";
readIntoBuffer(length);
readIntoBuffer(length, true);
return new String(buf, 0, length, "UTF-8");
}
private int readLength() throws IOException {
if(!hasLength()) throw new FormatException();
int length;
if(next >= 0) length = readUint7();
else if(next == Tag.INT8) length = readInt8();
else if(next == Tag.INT16) length = readInt16();
else if(next == Tag.INT32) length = readInt32();
else throw new IllegalStateException();
if(length < 0) throw new FormatException();
return length;
}
private boolean hasLength() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next >= 0 || next == Tag.INT8 || next == Tag.INT16
|| next == Tag.INT32;
}
public void skipString(int maxLength) throws IOException {
if(!hasString()) throw new FormatException();
hasLookahead = false;
int length = readLength();
if(length > maxLength) throw new FormatException();
hasLookahead = false;
int length = readInt32(false);
if(length < 0 || length > maxLength) throw new FormatException();
skip(length);
hasLookahead = false;
}
public boolean hasBytes() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.BYTES;
return next == BYTES;
}
public byte[] readBytes(int maxLength) throws IOException {
if(!hasBytes()) throw new FormatException();
consumeLookahead();
int length = readLength();
if(length > maxLength) throw new FormatException();
int length = readInt32(true);
if(length < 0 || length > maxLength) throw new FormatException();
if(length == 0) return EMPTY_BUFFER;
byte[] b = new byte[length];
readIntoBuffer(b, length);
readIntoBuffer(b, length, true);
return b;
}
public void skipBytes(int maxLength) throws IOException {
if(!hasBytes()) throw new FormatException();
hasLookahead = false;
int length = readLength();
if(length > maxLength) throw new FormatException();
hasLookahead = false;
int length = readInt32(false);
if(length < 0 || length > maxLength) throw new FormatException();
skip(length);
hasLookahead = false;
}
public boolean hasList() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.LIST;
return next == LIST;
}
public void readListStart() throws IOException {
@@ -385,7 +254,7 @@ class ReaderImpl implements Reader {
private boolean hasEnd() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.END;
return next == END;
}
public void readListEnd() throws IOException {
@@ -404,24 +273,10 @@ class ReaderImpl implements Reader {
hasLookahead = false;
}
private void skipObject() throws IOException {
if(hasBoolean()) skipBoolean();
else if(hasIntAny()) skipIntAny();
else if(hasFloat32()) skipFloat32();
else if(hasFloat64()) skipFloat64();
else if(hasString()) skipString(Integer.MAX_VALUE);
else if(hasBytes()) skipBytes(Integer.MAX_VALUE);
else if(hasList()) skipList();
else if(hasMap()) skipMap();
else if(hasStruct()) skipStruct();
else if(hasNull()) skipNull();
else throw new FormatException();
}
public boolean hasMap() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.MAP;
return next == MAP;
}
public void readMapStart() throws IOException {
@@ -450,14 +305,14 @@ class ReaderImpl implements Reader {
public boolean hasStruct() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.STRUCT;
return next == STRUCT;
}
public boolean hasStruct(int id) throws IOException {
if(id < 0 || id > 255) throw new IllegalArgumentException();
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.STRUCT && (nextStructId & 0xFF) == id;
return next == STRUCT && (nextStructId & 0xFF) == id;
}
public void readStructStart(int id) throws IOException {
@@ -483,7 +338,7 @@ class ReaderImpl implements Reader {
public boolean hasNull() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.NULL;
return next == NULL;
}
public void readNull() throws IOException {

View File

@@ -16,7 +16,7 @@ class SerialComponentImpl implements SerialComponent {
}
public int getSerialisedStructStartLength(int id) {
// STRUCT tag, ID
// STRUCT tag, 8-bit ID
return 2;
}
@@ -26,14 +26,7 @@ class SerialComponentImpl implements SerialComponent {
}
public int getSerialisedUniqueIdLength() {
// BYTES tag, length spec, bytes
return 1 + getSerialisedLengthSpecLength(UniqueId.LENGTH)
+ UniqueId.LENGTH;
}
private int getSerialisedLengthSpecLength(int length) {
if(length < 0) throw new IllegalArgumentException();
// Uint7, int16 or int32
return length <= Byte.MAX_VALUE ? 1 : length <= Short.MAX_VALUE ? 3 : 5;
// BYTES tag, 32-bit length, bytes
return 5 + UniqueId.LENGTH;
}
}

View File

@@ -2,19 +2,15 @@ package org.briarproject.serial;
interface Tag {
byte FALSE = (byte) 0xFF;
byte TRUE = (byte) 0xFE;
byte INT8 = (byte) 0xFD;
byte INT16 = (byte) 0xFC;
byte INT32 = (byte) 0xFB;
byte INT64 = (byte) 0xFA;
byte FLOAT32 = (byte) 0xF9;
byte FLOAT64 = (byte) 0xF8;
byte STRING = (byte) 0xF7;
byte BYTES = (byte) 0xF6;
byte LIST = (byte) 0xF5;
byte MAP = (byte) 0xF4;
byte STRUCT = (byte) 0xF3;
byte END = (byte) 0xF2;
byte NULL = (byte) 0xF1;
byte FALSE = 0;
byte TRUE = 1;
byte INTEGER = 2;
byte FLOAT = 3;
byte STRING = 4;
byte BYTES = 5;
byte LIST = 6;
byte MAP = 7;
byte STRUCT = 8;
byte END = 9;
byte NULL = 10;
}

View File

@@ -1,5 +1,11 @@
package org.briarproject.serial;
import static org.briarproject.serial.Tag.FALSE;
import static org.briarproject.serial.Tag.FLOAT;
import static org.briarproject.serial.Tag.INTEGER;
import static org.briarproject.serial.Tag.STRING;
import static org.briarproject.serial.Tag.TRUE;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -39,44 +45,16 @@ class WriterImpl implements Writer {
}
public void writeBoolean(boolean b) throws IOException {
if(b) write(Tag.TRUE);
else write(Tag.FALSE);
if(b) write(TRUE);
else write(FALSE);
}
public void writeUint7(byte b) throws IOException {
if(b < 0) throw new IllegalArgumentException();
write(b);
public void writeInteger(long l) throws IOException {
write(INTEGER);
writeInt64(l);
}
public void writeInt8(byte b) throws IOException {
write(Tag.INT8);
write(b);
}
public void writeInt16(short s) throws IOException {
write(Tag.INT16);
write((byte) (s >> 8));
write((byte) ((s << 8) >> 8));
}
public void writeInt32(int i) throws IOException {
write(Tag.INT32);
writeInt32Bits(i);
}
private void writeInt32Bits(int i) throws IOException {
write((byte) (i >> 24));
write((byte) ((i << 8) >> 24));
write((byte) ((i << 16) >> 24));
write((byte) ((i << 24) >> 24));
}
public void writeInt64(long l) throws IOException {
write(Tag.INT64);
writeInt64Bits(l);
}
private void writeInt64Bits(long l) throws IOException {
private void writeInt64(long l) throws IOException {
write((byte) (l >> 56));
write((byte) ((l << 8) >> 56));
write((byte) ((l << 16) >> 56));
@@ -87,41 +65,24 @@ class WriterImpl implements Writer {
write((byte) ((l << 56) >> 56));
}
public void writeIntAny(long l) throws IOException {
if(l >= 0 && l <= Byte.MAX_VALUE)
writeUint7((byte) l);
else if(l >= Byte.MIN_VALUE && l <= Byte.MAX_VALUE)
writeInt8((byte) l);
else if(l >= Short.MIN_VALUE && l <= Short.MAX_VALUE)
writeInt16((short) l);
else if(l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE)
writeInt32((int) l);
else writeInt64(l);
}
public void writeFloat32(float f) throws IOException {
write(Tag.FLOAT32);
writeInt32Bits(Float.floatToRawIntBits(f));
}
public void writeFloat64(double d) throws IOException {
write(Tag.FLOAT64);
writeInt64Bits(Double.doubleToRawLongBits(d));
public void writeFloat(double d) throws IOException {
write(FLOAT);
writeInt64(Double.doubleToRawLongBits(d));
}
public void writeString(String s) throws IOException {
byte[] b = s.getBytes("UTF-8");
write(Tag.STRING);
write(STRING);
writeLength(b.length);
write(b);
}
private void writeLength(int i) throws IOException {
assert i >= 0;
// Fun fact: it's never worth writing a length as an int8
if(i <= Byte.MAX_VALUE) writeUint7((byte) i);
else if(i <= Short.MAX_VALUE) writeInt16((short) i);
else writeInt32(i);
write((byte) (i >> 24));
write((byte) ((i << 8) >> 24));
write((byte) ((i << 16) >> 24));
write((byte) ((i << 24) >> 24));
}
public void writeBytes(byte[] b) throws IOException {
@@ -138,13 +99,14 @@ class WriterImpl implements Writer {
private void writeObject(Object o) throws IOException {
if(o instanceof Boolean) writeBoolean((Boolean) o);
else if(o instanceof Byte) writeIntAny((Byte) o);
else if(o instanceof Short) writeIntAny((Short) o);
else if(o instanceof Integer) writeIntAny((Integer) o);
else if(o instanceof Long) writeIntAny((Long) o);
else if(o instanceof Float) writeFloat32((Float) o);
else if(o instanceof Double) writeFloat64((Double) o);
else if(o instanceof Byte) writeInteger((Byte) o);
else if(o instanceof Short) writeInteger((Short) o);
else if(o instanceof Integer) writeInteger((Integer) o);
else if(o instanceof Long) writeInteger((Long) o);
else if(o instanceof Float) writeFloat((Float) o);
else if(o instanceof Double) writeFloat((Double) o);
else if(o instanceof String) writeString((String) o);
else if(o instanceof byte[]) writeBytes((byte[]) o);
else if(o instanceof Bytes) writeBytes(((Bytes) o).getBytes());
else if(o instanceof List<?>) writeList((List<?>) o);
else if(o instanceof Map<?, ?>) writeMap((Map<?, ?>) o);