Interface DataBuf

All Superinterfaces:
AutoCloseable
All Known Subinterfaces:
DataBuf.Mutable

public interface DataBuf extends AutoCloseable
Represents an immutable buffer which is essentially a wrapper around some kind of readable buffer. By default, CloudNet wraps the netty ByteBuf meaning that read operations are deferred to an underlying byte array of nio byte buffer.

However, a data buf does not allow (in comparison to other wrappers) the random access to bytes at specific positions (for example using a netty ByteBuf buf.getByte(index) would be possible, but isn't in this buffer). But it must be possible for a reader to store the current position of the buffer and return to it (for example after reading). This is done by starting a transaction using startTransaction(), reading or writing to the buffer and restoring the previous position by using redoTransaction(). Note: This will not remove bytes written to the buffer, other write operations will however start from the original index and override the written bytes.

Other operations should work as expected on a buffer, reading should always start from the head of the buffer, reflecting the operation over all other readers. If one reader reads a byte from the buffer, the next one will start at the second byte in the buffer, not the first one.

Buffers are not required to be thread safe, they can but should be treated specially in these cases. Concurrent read and/or write operations will therefore produce (by default) different results when spread over threads.

Buffers should avoid memory leaks by ensuring to release their content after the last byte of the buffer was read. The behaviour can be influenced by acquiring them using acquire(). The buffer will only be released if every place that acquired the buffer has released it using release() or close(). In rare cases it might be necessary to release a buffer even if it's acquired, use forceRelease() in that case.

To prevent exceptions during reading, it's worth noting that using readableBytes() > 0 it is possible to verify that there are still bytes left in the buffer to read.

It is not recommended using any constructor to create an instance of a data buf - you should obtain a factory for them and create your instance using the given factory methods.

Since:
4.0
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Interface
    Description
    static interface 
    Represents a mutable version of a data buf.
  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    Get if the current buffer is still accessible or if it was released already.
    Acquires this buffer once.
    int
    Get the amount of acquires that this data buf has.
    Converts this immutable buffer to a mutable one.
    void
    Explicitly releases all data associated with this buffer making it unavailable for further reads.
    Creates a new, empty data buffer using the default buffer factory (currently a netty buffer factory).
    void
    Explicitly releases all data associated with this buffer making it unavailable for further reads.
    int
    Get the number of remaining bytes in the buffer until the buffer gets released (when enabled).
    boolean
    Reads a boolean from this buffer at the current reader index.
    byte
    Reads a byte from this buffer at the current reader index.
    byte[]
    Reads the next array of bytes from the buffer.
    char
    Reads a 16-bit (UTF-16) char from this buffer at the current reader index.
    Reads the next data buf from the buffer.
    double
    Reads a 64-bit double from this buffer at the current reader index.
    float
    Reads a 32-bit float from this buffer at the current reader index.
    int
    Reads a 32-bit integer from this buffer at the current reader index.
    long
    Reads a 64-bit long from this buffer at the current reader index.
    <T> T
    readNullable(@NonNull Function<DataBuf,T> readerWhenNonNull)
    Reads the next requested data from the buffer.
    <T> T
    readNullable(@NonNull Function<DataBuf,T> readerWhenNonNull, T valueWhenNull)
    Reads the next requested data from the buffer.
    <T> T
    Reads the next object from the buffer at the current reader index.
    <T> T
    Reads the next object from the buffer at the current reader index.
    short
    Reads a 16-bit short from this buffer at the current reader index.
    Reads the next UTF-8 encoded string from the buffer.
    Reads the next unique id from the buffer at the current reader index.
    Redoes the currently running transaction on the buffer.
    void
    Explicitly releases all data associated with this buffer making it unavailable for further reads.
    Starts a transaction to the buffer.
    byte[]
    Converts the remaining bytes in this buffer into a byte array.
  • Method Details

    • empty

      @NonNull static DataBuf.Mutable empty()
      Creates a new, empty data buffer using the default buffer factory (currently a netty buffer factory).
      Returns:
      a new empty buffer which is mutable.
    • readBoolean

      boolean readBoolean()
      Reads a boolean from this buffer at the current reader index. Exactly one byte is read from the buffer.
      Returns:
      the boolean representation of the byte at the current position.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
    • readByte

      byte readByte()
      Reads a byte from this buffer at the current reader index. Exactly one byte is read from the buffer.
      Returns:
      the byte at the current reader position.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
    • readInt

      int readInt()
      Reads a 32-bit integer from this buffer at the current reader index. Exactly four bytes are read from the buffer.
      Returns:
      the next integer in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than four bytes to read.
      IllegalStateException - if this buffer was released.
    • readShort

      short readShort()
      Reads a 16-bit short from this buffer at the current reader index. Exactly two bytes are read from the buffer.
      Returns:
      the next short in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than two bytes to read.
      IllegalStateException - if this buffer was released.
    • readLong

      long readLong()
      Reads a 64-bit long from this buffer at the current reader index. Exactly eight bytes are read from the buffer.
      Returns:
      the next long in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than eight bytes to read.
      IllegalStateException - if this buffer was released.
    • readFloat

      float readFloat()
      Reads a 32-bit float from this buffer at the current reader index. Exactly four bytes are read from the buffer.
      Returns:
      the next float in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than four bytes to read.
      IllegalStateException - if this buffer was released.
    • readDouble

      double readDouble()
      Reads a 64-bit double from this buffer at the current reader index. Exactly eight bytes are read from the buffer.
      Returns:
      the next double in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than eight bytes to read.
      IllegalStateException - if this buffer was released.
    • readChar

      char readChar()
      Reads a 16-bit (UTF-16) char from this buffer at the current reader index. Exactly two bytes are read from the buffer.
      Returns:
      the next UTF-16 char in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than two bytes to read.
      IllegalStateException - if this buffer was released.
    • readByteArray

      byte[] readByteArray()
      Reads the next array of bytes from the buffer. A byte array is serialized in a special way. The bytes in the buffer are prefixed with the number of bytes in the array. Two steps are made to read an array from the buffer:
      1. The number of bytes in the following array are read from the buffer (by default a var int).
      2. The number of bytes the array is prefixed with are read from the buffer and put into a new array.

      As the operation is dynamic there is no way to pre-calculate the amount of bytes needed to read the next byte array.

      Returns:
      the next byte array in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are fewer bytes than expected in the buffer.
      IllegalStateException - if this buffer was released.
    • readUniqueId

      @NonNull @NonNull UUID readUniqueId()
      Reads the next unique id from the buffer at the current reader index. The operation reads two longs from the buffer: the most significant bits of the unique id, and the least significant bits of the unique id. This totals to exactly sixteen bytes which are read from the buffer.
      Returns:
      the next unique id in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are less than sixteen bytes to read.
      IllegalStateException - if this buffer was released.
    • readString

      @NonNull @NonNull String readString()
      Reads the next UTF-8 encoded string from the buffer. A string during write is converted to a byte array containing all bytes in UTF-8 form. Reading just reverses this operation. See readByteArray() for an explanation how the read operation works in detail (it's the same operation, the result is just wrapped using the string constructor).
      Returns:
      the next string in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are fewer bytes than expected in the buffer.
      IllegalStateException - if this buffer was released.
    • readDataBuf

      @NonNull @NonNull DataBuf readDataBuf()
      Reads the next data buf from the buffer. A data buf write works like a byte array write operation because the buffer is essentially just wrapping a byte array. See readByteArray() about the expected format.

      Buffers are not expected to be cross-implementation-compatible. For instance, a netty buffer can only read and write netty buffers.

      Returns:
      the data buf in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are fewer bytes than expected in the buffer.
      IllegalStateException - if this buffer was released.
    • toByteArray

      byte[] toByteArray()
      Converts the remaining bytes in this buffer into a byte array. This operation moves the reader index to the end of the buffer.
      Returns:
      the remaining bytes in this buffer converted to a byte array.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
    • readObject

      <T> T readObject(@NonNull @NonNull Class<T> type)
      Reads the next object from the buffer at the current reader index. The object is read using the default object mapper of the system.
      Type Parameters:
      T - the generic type of the object to read.
      Parameters:
      type - the type of the object to read.
      Returns:
      the next object in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
      See Also:
    • readObject

      <T> T readObject(@NonNull @NonNull Type type)
      Reads the next object from the buffer at the current reader index. The object is read using the default object mapper of the system.
      Type Parameters:
      T - the generic type of the object to read.
      Parameters:
      type - the type of the object to read.
      Returns:
      the next object in the buffer at the current reader index.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
      See Also:
    • readNullable

      @Nullable <T> T readNullable(@NonNull @NonNull Function<DataBuf,T> readerWhenNonNull)
      Reads the next requested data from the buffer. This method call is equivalent to readNullable(readerWhenNonNull, null).
      Type Parameters:
      T - the generic type of the data to read.
      Parameters:
      readerWhenNonNull - the reader to read the data from the buffer when the next value is non-null.
      Returns:
      the value read from the buffer or the fallback value when the buffered contained null at the position.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
    • readNullable

      <T> T readNullable(@NonNull @NonNull Function<DataBuf,T> readerWhenNonNull, @Nullable T valueWhenNull)
      Reads the next requested data from the buffer. To determine whether the given reader for further reading should be called, the boolean before the actual data is read. If the boolean is true, the following data is present (non-null), otherwise the given value to return when null is returned.
      Type Parameters:
      T - the generic type of the data to read.
      Parameters:
      readerWhenNonNull - the reader to read the data from the buffer when the next value is non-null.
      valueWhenNull - the value to return when the buffer contains a null value at the current reader index.
      Returns:
      the value read from the buffer or the fallback value when the buffered contained null at the position.
      Throws:
      IndexOutOfBoundsException - if there are no more bytes to read.
      IllegalStateException - if this buffer was released.
    • readableBytes

      int readableBytes()
      Get the number of remaining bytes in the buffer until the buffer gets released (when enabled).
      Returns:
      the number of remaining bytes in the buffer.
    • startTransaction

      @NonNull @NonNull DataBuf startTransaction()
      Starts a transaction to the buffer. Starting a transaction while another transaction is active will override the current transaction marker. A transaction can be redone by using redoTransaction().
      Returns:
      the same instance as used to call the method, for chaining.
    • redoTransaction

      @NonNull @NonNull DataBuf redoTransaction()
      Redoes the currently running transaction on the buffer. If no transaction was started before, the reader and writer index will go back to 0.
      Returns:
      the same instance as used to call the method, for chaining.
      Throws:
      IndexOutOfBoundsException - if an illegal action was made to buffer moving the reader or writer index.
    • asMutable

      Converts this immutable buffer to a mutable one. There is no need to copy the underlying byte tracker, meaning that all writes will be reflected into this buffer and vise-versa.
      Returns:
      a mutable variant of this buffer.
    • accessible

      boolean accessible()
      Get if the current buffer is still accessible or if it was released already.
      Returns:
      if the current buffer is still accessible.
    • acquires

      int acquires()
      Get the amount of acquires that this data buf has. Initially a data buf is acquired once.
      Returns:
      the amount of acquires. A value smaller or equal to zero means that the buffer was released.
    • acquire

      Acquires this buffer once. If a buffer gets acquired, further calls to release() will decrease the count, but only release the buffer if there were more release than acquire calls.
      Returns:
      the same instance as used to call the method, for chaining.
    • release

      void release()
      Explicitly releases all data associated with this buffer making it unavailable for further reads. This method only decreases the acquire count of the buffer in case it was acquired at least once.
    • forceRelease

      void forceRelease()
      Explicitly releases all data associated with this buffer making it unavailable for further reads. This method does not check if anyone acquired the buffer, it will be released in any case.
    • close

      void close()
      Explicitly releases all data associated with this buffer making it unavailable for further reads. This method does nothing if releasing was disables before calling this method.
      Specified by:
      close in interface AutoCloseable