at.yawk.dbus.protocol.object.AlignableByteBuf Maven / Gradle / Ivy
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package at.yawk.dbus.protocol.object;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCounted;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
/**
* @author yawkat
*/
@ToString
@EqualsAndHashCode
public class AlignableByteBuf implements ReferenceCounted {
@Getter private final ByteBuf buffer;
private final int messageOffset;
private final int baseAlignment;
// visible for testing
public AlignableByteBuf(ByteBuf buffer, int messageOffset, int baseAlignment) {
this.buffer = buffer;
this.messageOffset = messageOffset;
this.baseAlignment = baseAlignment;
}
public static AlignableByteBuf decoding(ByteBuf wrapping) {
return decoding(wrapping, 1 << 30);
}
public static AlignableByteBuf decoding(ByteBuf wrapping, int baseAlignment) {
return new AlignableByteBuf(wrapping, -wrapping.readerIndex(), baseAlignment);
}
/**
* Create a new {@link AlignableByteBuf} from the given message buffer. The message must start at {@code
* buffer[0]}.
*/
public static AlignableByteBuf encoding(ByteBuf wrapping) {
return new AlignableByteBuf(wrapping, 0, 1 << 30);
}
/**
* Create a new {@link AlignableByteBuf} from a buffer that is known to be aligned to a block boundary with the
* given block size.
*
* @param existingAlignment the alignment of the given buffer.
*/
public static AlignableByteBuf fromAlignedBuffer(ByteBuf buffer, int existingAlignment) {
return new AlignableByteBuf(buffer, 0, existingAlignment);
}
private int calculateAlignmentOffset(int position, int alignment) {
return (alignment - ((this.messageOffset + position) % alignment)) % alignment;
}
private boolean canAlign(int alignment) {
return (baseAlignment % alignment) == 0;
}
private void checkAlign(int alignment) {
if (!canAlign(alignment)) {
throw new IllegalArgumentException(
"Cannot align to boundary " + alignment + ": base boundary is " + baseAlignment);
}
}
public boolean canAlignRead(int alignment) {
if (!canAlign(alignment)) { return false; }
int toPad = calculateAlignmentOffset(getBuffer().readerIndex(), alignment);
return getBuffer().readableBytes() >= toPad;
}
public void alignRead(int alignment) {
checkAlign(alignment);
int toPad = calculateAlignmentOffset(getBuffer().readerIndex(), alignment);
for (int i = 0; i < toPad; i++) {
if (getBuffer().readByte() != 0) {
throw new DeserializerException("Non-null byte in alignment padding");
}
}
}
public boolean canAlignWrite(int alignment) {
if (!canAlign(alignment)) { return false; }
int toPad = calculateAlignmentOffset(getBuffer().writerIndex(), alignment);
return getBuffer().writableBytes() >= toPad;
}
public void alignWrite(int alignment) {
checkAlign(alignment);
int toPad = calculateAlignmentOffset(getBuffer().writerIndex(), alignment);
getBuffer().writeZero(toPad);
}
public boolean isReadable() {
return getBuffer().isReadable();
}
public boolean isReadable(int size) {
return getBuffer().isReadable(size);
}
public boolean isWritable() {
return getBuffer().isWritable();
}
public boolean isWritable(int size) {
return getBuffer().isWritable(size);
}
public int readableBytes() {
return getBuffer().readableBytes();
}
public int writableBytes() {
return getBuffer().writableBytes();
}
public int readerIndex() {
return getBuffer().readerIndex();
}
public AlignableByteBuf readerIndex(int readerIndex) {
getBuffer().readerIndex(readerIndex);
return this;
}
public int writerIndex() {
return getBuffer().writerIndex();
}
public AlignableByteBuf writerIndex(int writerIndex) {
getBuffer().writerIndex(writerIndex);
return this;
}
public int readInt() {
return getBuffer().readInt();
}
public int readUnsignedMedium() {
return getBuffer().readUnsignedMedium();
}
public int readMedium() {
return getBuffer().readMedium();
}
public int readUnsignedShort() {
return getBuffer().readUnsignedShort();
}
public short readShort() {
return getBuffer().readShort();
}
public byte readByte() {
return getBuffer().readByte();
}
public boolean readBoolean() {
return getBuffer().readBoolean();
}
public long readUnsignedInt() {
return getBuffer().readUnsignedInt();
}
public long readLong() {
return getBuffer().readLong();
}
public char readChar() {
return getBuffer().readChar();
}
public float readFloat() {
return getBuffer().readFloat();
}
public double readDouble() {
return getBuffer().readDouble();
}
public ByteBuf readBytes(int length) {
return getBuffer().readBytes(length);
}
public AlignableByteBuf readBytes(byte[] dst) {
getBuffer().readBytes(dst);
return this;
}
public AlignableByteBuf writeBoolean(boolean value) {
getBuffer().writeBoolean(value);
return this;
}
public AlignableByteBuf writeByte(int value) {
getBuffer().writeByte(value);
return this;
}
public AlignableByteBuf writeShort(int value) {
getBuffer().writeShort(value);
return this;
}
public AlignableByteBuf writeMedium(int value) {
getBuffer().writeMedium(value);
return this;
}
public AlignableByteBuf writeInt(int value) {
getBuffer().writeInt(value);
return this;
}
public AlignableByteBuf writeLong(long value) {
getBuffer().writeLong(value);
return this;
}
public AlignableByteBuf writeChar(int value) {
getBuffer().writeChar(value);
return this;
}
public AlignableByteBuf writeFloat(float value) {
getBuffer().writeFloat(value);
return this;
}
public AlignableByteBuf writeDouble(double value) {
getBuffer().writeDouble(value);
return this;
}
public AlignableByteBuf writeBytes(ByteBuf src) {
getBuffer().writeBytes(src);
return this;
}
public AlignableByteBuf writeBytes(byte[] src) {
getBuffer().writeBytes(src);
return this;
}
@Override
public int refCnt() {
return getBuffer().refCnt();
}
@Override
public ReferenceCounted retain() {
getBuffer().retain();
return this;
}
@Override
public ReferenceCounted retain(int increment) {
getBuffer().retain(increment);
return this;
}
@Override
public ReferenceCounted touch() {
getBuffer().touch();
return this;
}
@Override
public ReferenceCounted touch(Object hint) {
getBuffer().touch(hint);
return this;
}
@Override
public boolean release() {
return getBuffer().release();
}
@Override
public boolean release(int decrement) {
return getBuffer().release(decrement);
}
}