Interface NetworkBuffer


public sealed interface NetworkBuffer
A mutable byte buffer that reads and writes network protocol data through NetworkBuffer.Types.

Buffers keep separate read and write indexes. They come in two flavors:

  • Static buffers have no resize strategy, so writes past their capacity fail. They are created with staticBuffer(long).
  • Resizable buffers grow when a write needs more room and are created with resizableBuffer().
Basic Usage:
NetworkBuffer buffer = NetworkBuffer.resizableBuffer();
buffer.write(NetworkBuffer.INT, 42);
buffer.write(NetworkBuffer.STRING, "Hello");

int value = buffer.read(NetworkBuffer.INT);
String text = buffer.read(NetworkBuffer.STRING);
Custom Types with Templates:
record MyData(int id, String name) {
    static final NetworkBuffer.Type<MyData> SERIALIZER = NetworkBufferTemplate.template(
            NetworkBuffer.INT, MyData::id,
            NetworkBuffer.STRING, MyData::name,
            MyData::new);
}

MyData data = new MyData(1, "Test");
byte[] bytes = NetworkBuffer.makeArray(MyData.SERIALIZER, data);
NetworkBuffer buffer = NetworkBuffer.wrap(bytes, 0, bytes.length);
MyData value = buffer.read(MyData.SERIALIZER); // MyData[id=1, name=Test]

Buffers are not thread safe, because they track their read and write indexes.

See Also:
  • Field Details

  • Method Details

    • Enum

      static <E extends Enum<E>> NetworkBuffer.Type<E> Enum(Class<E> enumClass)
      Creates a type for the constants of an enum, encoded as a VAR_INT of the ordinal. Reading an ordinal with no matching constant throws IndexOutOfBoundsException.
      Type Parameters:
      E - the enum type
      Parameters:
      enumClass - the enum class
      Returns:
      the enum type
    • EnumSet

      static <E extends Enum<E>> NetworkBuffer.Type<EnumSet<E>> EnumSet(Class<E> enumClass)
      Creates a type for a set of enum constants, encoded as a FixedBitSet(int) with one bit per constant in ordinal order.
      Type Parameters:
      E - the enum type
      Parameters:
      enumClass - the enum class
      Returns:
      the enum set type
    • FixedBitSet

      static NetworkBuffer.Type<BitSet> FixedBitSet(int length)
      Creates a type for a bit set of exactly length bits, stored in (length + 7) / 8 bytes.
      Parameters:
      length - the bit count, which must not be negative
      Returns:
      the fixed length bit set type
    • FixedRawBytes

      static NetworkBuffer.Type<byte[]> FixedRawBytes(int length)
      Creates a type for exactly length bytes, unlike RAW_BYTES which reads every byte left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length byte type
    • FixedRawShorts

      static NetworkBuffer.Type<short[]> FixedRawShorts(int length)
      Creates a type for exactly length shorts, unlike RAW_SHORTS which reads every short left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length short type
    • FixedRawInts

      static NetworkBuffer.Type<int[]> FixedRawInts(int length)
      Creates a type for exactly length ints, unlike RAW_INTS which reads every int left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length int type
    • FixedRawLongs

      static NetworkBuffer.Type<long[]> FixedRawLongs(int length)
      Creates a type for exactly length longs, unlike RAW_LONGS which reads every long left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length long type
    • FixedRawFloats

      static NetworkBuffer.Type<float[]> FixedRawFloats(int length)
      Creates a type for exactly length floats, unlike RAW_FLOATS which reads every float left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length float type
    • FixedRawDoubles

      static NetworkBuffer.Type<double[]> FixedRawDoubles(int length)
      Creates a type for exactly length doubles, unlike RAW_DOUBLES which reads every double left in the buffer.
      Parameters:
      length - the element count, which must not be negative
      Returns:
      the fixed length double type
    • Lazy

      static <T extends @UnknownNullability Object> NetworkBuffer.Type<T> Lazy(Supplier<NetworkBuffer.Type<T>> supplier)
      Creates a type that gets its implementation from supplier on first use. The supplier should be thread safe, because first uses from several threads at once can each call it.
      Type Parameters:
      T - the value type
      Parameters:
      supplier - the supplier of the type
      Returns:
      the lazy type
    • TypedNBT

      static <T extends @UnknownNullability Object> NetworkBuffer.Type<T> TypedNBT(Codec<T> serializer)
      Creates a type that encodes values with serializer as NBT, and reads them with UNTRUSTED_NBT. Reading and writing throw IllegalStateException when the buffer has no registries(), and IllegalArgumentException when the codec fails.
      Type Parameters:
      T - the value type
      Parameters:
      serializer - the codec for the values
      Returns:
      the NBT type
    • Either

      static <L,R> NetworkBuffer.Type<Either<L,R>> Either(NetworkBuffer.Type<L> left, NetworkBuffer.Type<R> right)
      Creates a type for an Either, encoded as a BOOLEAN that is true for a left value, followed by the value.
      Type Parameters:
      L - the left type
      R - the right type
      Parameters:
      left - the type of left values
      right - the type of right values
      Returns:
      the either type
    • Recursive

      static <T extends @UnknownNullability Object> NetworkBuffer.Type<T> Recursive(Function<? super NetworkBuffer.Type<T>, ? extends NetworkBuffer.Type<T>> func)
      Creates a type that refers to itself, such as a node that contains other nodes. func is called once, right away, with a type that delegates to the type it returns. That reference must not read or write before func returns.
      Type Parameters:
      T - the value type
      Parameters:
      func - the function that builds the type from a reference to itself
      Returns:
      the type returned by func
    • Tagged

      static <T extends @UnknownNullability Object, D> NetworkBuffer.Type<T> Tagged(NetworkBuffer.Type<D> discriminator, Function<? super T, ? extends D> discriminatorFromValue, Map<? super D, ? extends NetworkBuffer.Type<? extends T>> serializerMap, @Nullable @Nullable NetworkBuffer.Type<? extends T> fallback)
      Creates a type for the subtypes of T, encoded as the discriminator of each value followed by the value in the serializer mapped to that discriminator. The fallback serializer handles discriminators missing from serializerMap. Without a fallback, reading and writing throw UnsupportedOperationException for a missing discriminator.
      Type Parameters:
      T - the value type
      D - the discriminator type
      Parameters:
      discriminator - the type of the discriminator
      discriminatorFromValue - the discriminator of a value
      serializerMap - the serializer for each discriminator, which this method copies
      fallback - the serializer for other discriminators, or null for none
      Returns:
      the tagged type
      Throws:
      NullPointerException - if serializerMap contains a null key or value
    • Tagged

      static <T extends @UnknownNullability Object, D> NetworkBuffer.Type<T> Tagged(NetworkBuffer.Type<D> discriminator, Function<? super T, ? extends D> discriminatorFromValue, Map<? super D, ? extends NetworkBuffer.Type<? extends T>> serializerMap)
      Creates a tagged type with no fallback, so reading and writing throw UnsupportedOperationException for a discriminator missing from serializerMap.
      Type Parameters:
      T - the value type
      D - the discriminator type
      Parameters:
      discriminator - the type of the discriminator
      discriminatorFromValue - the discriminator of a value
      serializerMap - the serializer for each discriminator, which this method copies
      Returns:
      the tagged type
      Throws:
      NullPointerException - if serializerMap contains a null key or value
      See Also:
    • write

      <T extends @UnknownNullability Object> void write(NetworkBuffer.Type<T> type, T value) throws IndexOutOfBoundsException
      Writes a value at the writeIndex() and advances it past the value. The buffer is resized first when it needs more room and has a resize strategy.
      Type Parameters:
      T - the value type
      Parameters:
      type - the type of the value
      value - the value to write
      Throws:
      IndexOutOfBoundsException - if the value does not fit and the buffer cannot grow
      IllegalArgumentException - if this buffer is read-only
    • read

      Reads a value at the readIndex() and advances it past the value.
      Type Parameters:
      T - the value type
      Parameters:
      type - the type of the value
      Returns:
      the value
      Throws:
      IndexOutOfBoundsException - if the value extends past the capacity()
      IllegalArgumentException - if this buffer is a dummy
    • writeAt

      <T extends @UnknownNullability Object> void writeAt(long index, NetworkBuffer.Type<T> type, T value) throws IndexOutOfBoundsException
      Writes a value at index, leaving the writeIndex() unchanged.
      Type Parameters:
      T - the value type
      Parameters:
      index - the index to write at
      type - the type of the value
      value - the value to write
      Throws:
      IndexOutOfBoundsException - if the value does not fit and the buffer cannot grow
      IllegalArgumentException - if this buffer is read-only
    • readAt

      <T extends @UnknownNullability Object> T readAt(long index, NetworkBuffer.Type<T> type) throws IndexOutOfBoundsException
      Reads a value at index, leaving the readIndex() unchanged.
      Type Parameters:
      T - the value type
      Parameters:
      index - the index to read at
      type - the type of the value
      Returns:
      the value
      Throws:
      IndexOutOfBoundsException - if the value extends past the capacity()
      IllegalArgumentException - if this buffer is a dummy
    • copyTo

      void copyTo(long srcOffset, byte[] dest, int destOffset, int length)
      Copies length bytes starting at srcOffset into dest, ignoring the read and write indexes.
      Parameters:
      srcOffset - the index of the first byte to copy
      dest - the destination array
      destOffset - the index in dest to copy to
      length - the number of bytes to copy
      Throws:
      IndexOutOfBoundsException - if either range is out of bounds
      IllegalArgumentException - if this buffer is a dummy
    • copyTo

      void copyTo(long srcOffset, MemorySegment dest, long destOffset, long length)
      Copies length bytes starting at srcOffset into dest, ignoring the read and write indexes.
      Parameters:
      srcOffset - the index of the first byte to copy
      dest - the destination segment
      destOffset - the index in dest to copy to
      length - the number of bytes to copy
      Throws:
      IndexOutOfBoundsException - if either range is out of bounds
      IllegalArgumentException - if this buffer is a dummy, or dest is read-only
    • extractBytes

      byte[] extractBytes(Consumer<? super NetworkBuffer> extractor)
      Runs extractor on this buffer and returns a copy of the bytes it read, from the readIndex() before the call to the one after it.
      Parameters:
      extractor - the reads to capture
      Returns:
      the bytes read by extractor
      Throws:
      IllegalArgumentException - if this buffer is a dummy
    • clear

      NetworkBuffer clear()
      Sets the read and write indexes to 0. The stored bytes are not zeroed.
      Returns:
      this buffer
    • writeIndex

      long writeIndex()
      Returns the index of the next byte to write.
      Returns:
      the write index
    • readIndex

      long readIndex()
      Returns the index of the next byte to read.
      Returns:
      the read index
    • writeIndex

      NetworkBuffer writeIndex(long writeIndex)
      Sets the write index. The index is not validated.
      Parameters:
      writeIndex - the new write index
      Returns:
      this buffer
    • readIndex

      NetworkBuffer readIndex(long readIndex)
      Sets the read index. The index is not validated.
      Parameters:
      readIndex - the new read index
      Returns:
      this buffer
    • index

      NetworkBuffer index(long readIndex, long writeIndex)
      Sets both the read index and the write index. The indexes are not validated.
      Parameters:
      readIndex - the new read index
      writeIndex - the new write index
      Returns:
      this buffer
    • advanceWrite

      long advanceWrite(long length)
      Moves the write index forward by length.
      Parameters:
      length - the number of bytes to advance
      Returns:
      the previous write index
    • advanceRead

      long advanceRead(long length)
      Moves the read index forward by length.
      Parameters:
      length - the number of bytes to advance
      Returns:
      the previous read index
    • readableBytes

      long readableBytes()
      Returns the number of bytes between the read index and the write index, writeIndex() - readIndex().
      Returns:
      the readable bytes
    • writableBytes

      long writableBytes()
      Returns the number of bytes between the write index and the capacity, capacity() - writeIndex(). A buffer with a resize strategy can grow past this.
      Returns:
      the writable bytes
    • capacity

      long capacity()
      Returns the size of the memory backing this buffer. A dummy buffer reports Long.MAX_VALUE.
      Returns:
      the capacity
    • readOnly

      @Contract(pure=true, value="-> new") NetworkBuffer readOnly()
      Creates a read-only view of this buffer with the same indexes and registries, and no resize strategy. The view shares memory with this buffer until this buffer is resized, after which it keeps the old bytes.
      Returns:
      the read-only view
      Throws:
      IllegalArgumentException - if this buffer is a dummy
    • isReadOnly

      boolean isReadOnly()
      Returns whether this buffer rejects writes, as the views created by readOnly() do.
      Returns:
      true if this buffer is read-only
    • resize

      void resize(long newSize)
      Moves the contents of this buffer into new memory of newSize bytes, keeping the indexes. Buffers without a resize strategy can be resized this way too. Views created by readOnly() or slice(long, long, long, long) keep the old memory.
      Parameters:
      newSize - the new capacity, which must be greater than the current capacity
      Throws:
      IllegalArgumentException - if newSize is not greater than the current capacity
      IllegalArgumentException - if this buffer is read-only or a dummy
    • ensureWritable

      void ensureWritable(long length) throws IndexOutOfBoundsException
      Ensures that at least length bytes can be written at the writeIndex(), resizing the buffer with its resize strategy when needed.
      Parameters:
      length - the number of bytes, which must not be negative
      Throws:
      IllegalArgumentException - if length is negative, or this buffer is read-only
      IndexOutOfBoundsException - if the buffer is too small and has no resize strategy, or the strategy returns the current capacity
    • ensureReadable

      void ensureReadable(long length) throws IndexOutOfBoundsException
      Ensures that at least length bytes are readable, as counted by readableBytes().
      Parameters:
      length - the number of bytes, which must not be negative
      Throws:
      IllegalArgumentException - if length is negative
      IndexOutOfBoundsException - if fewer than length bytes are readable
    • compact

      void compact()
      Moves the readable bytes to the start of the buffer and lowers both indexes by the old read index. The capacity does not change.
      Throws:
      IllegalArgumentException - if this buffer is read-only or a dummy
    • copy

      NetworkBuffer copy(long index, long length, long readIndex, long writeIndex)
      Copies length bytes starting at index into a new buffer with the given indexes. The copy keeps the resize strategy and registries of this buffer.
      Parameters:
      index - the index of the first byte to copy
      length - the number of bytes to copy, which becomes the capacity of the copy
      readIndex - the read index of the copy
      writeIndex - the write index of the copy
      Returns:
      the new buffer
      Throws:
      IndexOutOfBoundsException - if the range is outside the capacity
      IllegalArgumentException - if this buffer is a dummy
    • copy

      default NetworkBuffer copy(long index, long length)
      Copies length bytes starting at index into a new buffer with the current indexes of this buffer.
      Parameters:
      index - the index of the first byte to copy
      length - the number of bytes to copy, which becomes the capacity of the copy
      Returns:
      the new buffer
      Throws:
      IndexOutOfBoundsException - if the range is outside the capacity
      IllegalArgumentException - if this buffer is a dummy
      See Also:
    • readChannel

      int readChannel(ReadableByteChannel channel) throws IOException
      Reads from channel into the writableBytes() of this buffer and advances the writeIndex(). The buffer is not resized.
      Parameters:
      channel - the channel to read from
      Returns:
      the number of bytes read
      Throws:
      IOException - if the channel fails or has reached the end of its stream
      IllegalArgumentException - if this buffer is a dummy
    • writeChannel

      boolean writeChannel(WritableByteChannel channel) throws IOException
      Writes the readableBytes() of this buffer to channel and advances the readIndex() by the number of bytes written.
      Parameters:
      channel - the channel to write to
      Returns:
      true if every readable byte was written
      Throws:
      IOException - if the channel fails
      IllegalArgumentException - if this buffer is a dummy
    • cipher

      void cipher(Cipher cipher, long start, long length)
      Encrypts or decrypts length bytes starting at start in place with cipher.
      Parameters:
      cipher - the cipher to update with the bytes
      start - the index of the first byte
      length - the number of bytes
      Throws:
      IllegalArgumentException - if this buffer is a dummy
    • compress

      long compress(long start, long length, NetworkBuffer output)
      Compresses length bytes starting at start with a Deflater into output at its write index, and advances the write index of output. The output is not resized, so it needs enough writable bytes for the compressed data.
      Parameters:
      start - the index of the first byte
      length - the number of bytes
      output - the buffer to write the compressed bytes to
      Returns:
      the number of compressed bytes written
      Throws:
      IllegalArgumentException - if either buffer is a dummy, or output is read-only
    • decompress

      long decompress(long start, long length, NetworkBuffer output) throws DataFormatException
      Decompresses length bytes starting at start with an Inflater into output at its write index, and advances the write index of output. The output is not resized.
      Parameters:
      start - the index of the first byte
      length - the number of bytes
      output - the buffer to write the decompressed bytes to
      Returns:
      the number of decompressed bytes written
      Throws:
      DataFormatException - if the data is invalid or incomplete, or does not fit in the writable bytes of output
      IllegalArgumentException - if either buffer is a dummy, or output is read-only
    • registries

      Returns the registries for types that need them, given when the buffer was created or set with registries(Registries).
      Returns:
      the registries, or null if there are none
    • registries

      void registries(@Nullable @Nullable Registries registries)
      Sets the registries for types that need them, replacing the ones given when the buffer was created. Buffers already created from this one by readOnly(), slice(long, long, long, long), or copy(long, long, long, long) keep their own registries.
      Parameters:
      registries - the registries, or null for none
    • slice

      @Contract(pure=true, value="_, _, _, _ -> new") NetworkBuffer slice(long offset, long byteLength, long readIndex, long writeIndex)
      A slice is an operation where the backing memory is used for the new buffer. Consider it a view over the backing memory region.
      Parameters:
      offset - the position to start the slice
      byteLength - the length of the slice, equal to capacity()
      readIndex - the read index
      writeIndex - the write index
      Returns:
      a new buffer
      Throws:
      IllegalArgumentException - if this buffer is a dummy
      API Note:
      With resized segments, you could observe behavior where you may see stale data or close arenas. To avoid this, do not use resizable segments in a way where they are written or resized like resize(long).
      Implementation Note:
      registries() are copied into the new buffer
    • builder

      static NetworkBuffer.Builder builder(long size)
      Creates a builder for a buffer with an initial capacity of size bytes. The buffer has no resize strategy and no registries unless the builder sets them.
      Parameters:
      size - the initial capacity, which must not be negative
      Returns:
      the new builder
    • staticBuffer

      static NetworkBuffer staticBuffer(long size, Registries registries)
      Creates a buffer with a capacity of size bytes and no resize strategy, so writes past the capacity throw IndexOutOfBoundsException.
      Parameters:
      size - the capacity
      registries - the registries for types that need them
      Returns:
      the new buffer
    • staticBuffer

      static NetworkBuffer staticBuffer(long size)
      Creates a buffer with a capacity of size bytes, no resize strategy, and no registries.
      Parameters:
      size - the capacity
      Returns:
      the new buffer
      See Also:
    • resizableBuffer

      static NetworkBuffer resizableBuffer(long initialSize, Registries registries)
      Creates a buffer with an initial capacity of initialSize bytes that grows with NetworkBuffer.AutoResize.DOUBLE.
      Parameters:
      initialSize - the initial capacity
      registries - the registries for types that need them
      Returns:
      the new buffer
    • resizableBuffer

      static NetworkBuffer resizableBuffer(long initialSize)
      Creates a buffer with an initial capacity of initialSize bytes that grows with NetworkBuffer.AutoResize.DOUBLE, and has no registries.
      Parameters:
      initialSize - the initial capacity
      Returns:
      the new buffer
    • resizableBuffer

      static NetworkBuffer resizableBuffer(Registries registries)
      Creates a buffer with an initial capacity of 256 bytes that grows with NetworkBuffer.AutoResize.DOUBLE.
      Parameters:
      registries - the registries for types that need them
      Returns:
      the new buffer
    • resizableBuffer

      static NetworkBuffer resizableBuffer()
      Creates a buffer with an initial capacity of 256 bytes that grows with NetworkBuffer.AutoResize.DOUBLE, and has no registries.
      Returns:
      the new buffer
    • wrap

      static NetworkBuffer wrap(MemorySegment segment, long readIndex, long writeIndex, @Nullable @Nullable Registries registries)
      Creates a buffer that reads and writes segment directly, with no resize strategy. Useful when you already have a memory segment.
      Parameters:
      segment - the memory to use
      readIndex - the readIndex()
      writeIndex - the writeIndex()
      registries - the registries(), or null
      Returns:
      the new buffer
    • wrap

      static NetworkBuffer wrap(MemorySegment segment, long readIndex, long writeIndex)
      Creates a buffer that reads and writes segment directly, with no resize strategy and no registries.
      Parameters:
      segment - the memory to use
      readIndex - the readIndex()
      writeIndex - the writeIndex()
      Returns:
      the new buffer
      See Also:
    • wrap

      static NetworkBuffer wrap(byte[] bytes, int readIndex, int writeIndex, @Nullable @Nullable Registries registries)
      Creates a buffer that reads and writes bytes directly, with no resize strategy. Useful when you already have a byte[].
      Parameters:
      bytes - the array to use
      readIndex - the readIndex()
      writeIndex - the writeIndex()
      registries - the registries(), or null
      Returns:
      the new buffer
    • wrap

      static NetworkBuffer wrap(byte[] bytes, int readIndex, int writeIndex)
      Creates a buffer that reads and writes bytes directly, with no resize strategy and no registries.
      Parameters:
      bytes - the array to use
      readIndex - the readIndex()
      writeIndex - the writeIndex()
      Returns:
      the new buffer
      See Also:
    • makeArray

      static byte[] makeArray(Consumer<? super NetworkBuffer> writing, @Nullable @Nullable Registries registries)
      Runs writing on a new resizable buffer and returns the bytes it wrote, in an array of exactly that length.
      Parameters:
      writing - the writes to capture
      registries - the registries for types that need them, or null
      Returns:
      the written bytes
    • makeArray

      static byte[] makeArray(Consumer<? super NetworkBuffer> writing)
      Runs writing on a new resizable buffer without registries and returns the bytes it wrote.
      Parameters:
      writing - the writes to capture
      Returns:
      the written bytes
      See Also:
    • makeArray

      static <T extends @UnknownNullability Object> byte[] makeArray(NetworkBuffer.Type<T> type, T value, @Nullable @Nullable Registries registries)
      Encodes value with type and returns the bytes, in an array of exactly that length.
      Type Parameters:
      T - the value type
      Parameters:
      type - the type of the value
      value - the value to encode
      registries - the registries for types that need them, or null
      Returns:
      the encoded bytes
    • makeArray

      static <T extends @UnknownNullability Object> byte[] makeArray(NetworkBuffer.Type<T> type, T value)
      Encodes value with type without registries and returns the bytes.
      Type Parameters:
      T - the value type
      Parameters:
      type - the type of the value
      value - the value to encode
      Returns:
      the encoded bytes
      See Also:
    • copy

      static void copy(NetworkBuffer srcBuffer, long srcOffset, NetworkBuffer dstBuffer, long dstOffset, long length)
      Copies length bytes from srcBuffer at srcOffset to dstBuffer at dstOffset, ignoring the read and write indexes of both buffers. dstBuffer is not resized.
      Parameters:
      srcBuffer - the buffer to copy from
      srcOffset - the index of the first byte to copy
      dstBuffer - the buffer to copy to
      dstOffset - the index in dstBuffer to copy to
      length - the number of bytes to copy
      Throws:
      IndexOutOfBoundsException - if either range is outside the capacity of its buffer
      IllegalArgumentException - if either buffer is a dummy, or dstBuffer is read-only
    • equals

      static boolean equals(NetworkBuffer buffer1, NetworkBuffer buffer2)
      Checks whether two buffers have the same capacity and the same bytes across it, ignoring their read and write indexes.
      Parameters:
      buffer1 - the first buffer
      buffer2 - the second buffer
      Returns:
      true if the contents are equal
      Throws:
      IllegalArgumentException - if either buffer is a dummy