All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.chronicle.wire.ValueIn Maven / Gradle / Ivy

/*
 * Copyright 2016-2020 chronicle.software
 *
 *       https://chronicle.software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.openhft.chronicle.wire;

import net.openhft.chronicle.bytes.*;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import net.openhft.chronicle.core.io.Resettable;
import net.openhft.chronicle.core.io.ValidatableUtil;
import net.openhft.chronicle.core.pool.ClassLookup;
import net.openhft.chronicle.core.scoped.ScopedResource;
import net.openhft.chronicle.core.util.*;
import net.openhft.chronicle.core.values.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.*;

import static net.openhft.chronicle.wire.SerializationStrategies.MARSHALLABLE;

/**
 * Represents an interface for reading values in various formats from a serialized data source.
 * This interface is part of the Chronicle Wire library, which is designed for high-performance
 * serialization and deserialization of data. It provides methods to read data types like text,
 * binary, numeric, and temporal values, as well as support for more complex types like collections
 * and marshallable objects.
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public interface ValueIn {
    /** A constant consumer that does nothing when accepting a {@link ValueIn}. */
    Consumer DISCARD = v -> {};

    // ---- Text / Strings section ----

    /**
     * Reads text data and applies a given bi-consumer to the text data and the provided object.
     *
     * @param t  The target object.
     * @param ts The bi-consumer that accepts the target object and the read text.
     * @param  Type of the target object.
     * @return The current WireIn instance.
     */
    @NotNull
    default  WireIn text(T t, @NotNull BiConsumer ts) {
        @Nullable final String text = text();
        ts.accept(t, text);
        return wireIn();
    }

    /**
     * Reads text data and appends it to the given StringBuilder. If the data is null, the StringBuilder is cleared.
     *
     * @param sb The StringBuilder to append the text data to.
     * @return The current WireIn instance.
     */
    @NotNull
    default WireIn text(@NotNull StringBuilder sb) {
        if (textTo(sb) == null)
            sb.setLength(0);
        return wireIn();
    }

    /**
     * Reads text data and returns the first character. If the data is null or empty, a null character is returned.
     *
     * @return The first character of the text data or '\u0000' if none.
     */
    default char character() {
        try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) {
            @Nullable CharSequence cs = textTo(stlSb.get());
            if (cs == null || cs.length() == 0)
                return '\u0000';

            return cs.charAt(0);
        }
    }

    /**
     * Reads text data into the provided Bytes object, which is then cleared.
     *
     * @param sdo The Bytes object to store the text data.
     * @return The current WireIn instance.
     */
    @NotNull
    default WireIn text(@NotNull Bytes sdo) {
        sdo.clear();
        textTo(sdo);
        return wireIn();
    }

    /**
     * Reads and returns the text data.
     *
     * @return The text data or null.
     */
    @Nullable
    String text();

    /**
     * Reads text data and appends it to the given StringBuilder.
     *
     * @param sb The StringBuilder to append the text data to.
     * @return The StringBuilder with appended text or null.
     */
    @Nullable
    StringBuilder textTo(@NotNull StringBuilder sb);

    /**
     * Reads text data into the provided Bytes object.
     *
     * @param bytes The Bytes object to store the text data.
     * @return The Bytes object with the text data or null.
     */
    @Nullable
    Bytes textTo(@NotNull Bytes bytes);

    /**
     * Reads byte data into the provided BytesOut object.
     *
     * @param toBytes The BytesOut object to store the byte data.
     * @return The current WireIn instance.
     */
    @NotNull
    WireIn bytes(@NotNull BytesOut toBytes);

    /**
     * Reads byte data into the provided BytesOut object with an option to clear the BytesOut before reading.
     *
     * @param toBytes The BytesOut object to store the byte data.
     * @param clearBytes If true, the BytesOut object will be cleared before reading.
     * @return The current WireIn instance.
     */
    default WireIn bytes(@NotNull BytesOut toBytes, boolean clearBytes) {
        if (clearBytes)
            toBytes.clear();
        return bytes(toBytes);
    }

    /**
     * Reads byte data into the provided BytesOut object.
     * This method acts as a semantic alias for {@link #bytes(BytesOut)} method.
     *
     * @param toBytes The BytesOut object to store the byte data.
     * @return The current WireIn instance.
     */
    @NotNull
    default WireIn bytesLiteral(@NotNull BytesOut toBytes) {
        return bytes(toBytes);
    }

    /**
     * Retrieves the byte data as a BytesStore object.
     * This method acts as a semantic alias for {@link #bytesStore()} method.
     *
     * @return The BytesStore object or null.
     */
    @Nullable
    default BytesStore bytesLiteral() {
        return bytesStore();
    }

    /**
     * Sets byte data to the provided PointerBytesStore.
     *
     * @param toBytes The PointerBytesStore to set the byte data.
     * @return The current WireIn instance.
     */
    @Nullable
    WireIn bytesSet(@NotNull PointerBytesStore toBytes);

    /**
     * Compares byte data with the provided BytesStore and uses the given BooleanConsumer based on the result.
     *
     * @param compareBytes The BytesStore to compare with.
     * @param consumer     The BooleanConsumer to be called based on the comparison result.
     * @return The current WireIn instance.
     */
    @NotNull
    WireIn bytesMatch(@NotNull BytesStore compareBytes, BooleanConsumer consumer);

    /**
     * Reads byte data using the provided ReadBytesMarshallable.
     *
     * @param bytesMarshallable The ReadBytesMarshallable to read the byte data.
     * @return The current WireIn instance.
     */
    @NotNull
    WireIn bytes(@NotNull ReadBytesMarshallable bytesMarshallable);

    /**
     * Retrieves the byte data as an array.
     *
     * @return The byte data as an array or null.
     */
    default byte @Nullable [] bytes() {
        return bytes((byte[]) null);
    }

    /**
     * Retrieves the byte data as an array with the option to reuse an existing byte array.
     *
     * @param using The existing byte array to use or null.
     * @return The byte data as an array or null.
     */
    byte @Nullable [] bytes(byte[] using);

    /**
     * Retrieves the byte data as a BytesStore object.
     *
     * @return The BytesStore object or null.
     */
    @Nullable
    default BytesStore bytesStore() {
        byte @Nullable [] bytes = bytes();
        return bytes == null ? null : BytesStore.wrap(bytes);
    }

    /**
     * Puts the byte data into the provided ByteBuffer.
     *
     * @param bb The ByteBuffer to put the byte data.
     */
    default void byteBuffer(@NotNull ByteBuffer bb) {
        bb.put(bytes());
    }

    /**
     * Provides the current WireIn instance.
     *
     * @return The current WireIn instance.
     */
    @NotNull
    WireIn wireIn();

    /**
     * Retrieves the length of the field in bytes, inclusive of any encoding and header character.
     *
     * @return The length of the field in bytes.
     */
    long readLength();

    /**
     * Skips the current value while reading.
     *
     * @return The current WireIn instance.
     */
    @NotNull
    WireIn skipValue();

    /**
     * Reads a boolean value and applies it to the provided consumer.
     *
     * @param t     The target object.
     * @param tFlag The consumer that accepts the target object and the read boolean value.
     * @return The current WireIn instance.
     * @param    The type of the target object.
     */
    @NotNull  WireIn bool(T t, @NotNull ObjBooleanConsumer tFlag);

    /**
     * Reads an 8-bit integer (byte) value and applies an ObjByteConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjByteConsumer.
     * @param t   The object to be passed to the ObjByteConsumer.
     * @param tb  The ObjByteConsumer that accepts the object and the read 8-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn int8(@NotNull T t, @NotNull ObjByteConsumer tb);

    /**
     * Reads an unsigned 8-bit integer (short) value and applies an ObjShortConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjShortConsumer.
     * @param t   The object to be passed to the ObjShortConsumer.
     * @param ti  The ObjShortConsumer that accepts the object and the read unsigned 8-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn uint8(@NotNull T t, @NotNull ObjShortConsumer ti);

    /**
     * Reads a 16-bit integer (short) value and applies an ObjShortConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjShortConsumer.
     * @param t   The object to be passed to the ObjShortConsumer.
     * @param ti  The ObjShortConsumer that accepts the object and the read 16-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn int16(@NotNull T t, @NotNull ObjShortConsumer ti);

    /**
     * Reads an unsigned 16-bit integer (int) value and applies an ObjIntConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjIntConsumer.
     * @param t   The object to be passed to the ObjIntConsumer.
     * @param ti  The ObjIntConsumer that accepts the object and the read unsigned 16-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn uint16(@NotNull T t, @NotNull ObjIntConsumer ti);

    /**
     * Reads a 32-bit integer (int) value and applies an ObjIntConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjIntConsumer.
     * @param t   The object to be passed to the ObjIntConsumer.
     * @param ti  The ObjIntConsumer that accepts the object and the read 32-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn int32(@NotNull T t, @NotNull ObjIntConsumer ti);

    /**
     * Reads an unsigned 32-bit integer (long) value and applies an ObjLongConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjLongConsumer.
     * @param t   The object to be passed to the ObjLongConsumer.
     * @param tl  The ObjLongConsumer that accepts the object and the read unsigned 32-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn uint32(@NotNull T t, @NotNull ObjLongConsumer tl);

    /**
     * Reads a 64-bit integer (long) value and applies an ObjLongConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjLongConsumer.
     * @param t   The object to be passed to the ObjLongConsumer.
     * @param tl  The ObjLongConsumer that accepts the object and the read 64-bit integer value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn int64(@NotNull T t, @NotNull ObjLongConsumer tl);

    /**
     * Reads a 32-bit floating-point (float) value and applies an ObjFloatConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjFloatConsumer.
     * @param t   The object to be passed to the ObjFloatConsumer.
     * @param tf  The ObjFloatConsumer that accepts the object and the read 32-bit floating-point value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn float32(@NotNull T t, @NotNull ObjFloatConsumer tf);

    /**
     * Reads a 64-bit floating-point (double) value and applies an ObjDoubleConsumer with the provided object and the read value.
     *
     * @param  The type of object to be passed to the ObjDoubleConsumer.
     * @param t   The object to be passed to the ObjDoubleConsumer.
     * @param td  The ObjDoubleConsumer that accepts the object and the read 64-bit floating-point value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn float64(@NotNull T t, @NotNull ObjDoubleConsumer td);

    @NotNull  WireIn time(@NotNull T t, @NotNull BiConsumer setLocalTime);

    /**
     * Reads a ZonedDateTime from the wire and applies it to a given object using the provided BiConsumer.
     *
     * @param             The type of object to be passed to the BiConsumer.
     * @param t              The object to be passed to the BiConsumer.
     * @param tZonedDateTime The BiConsumer that accepts the object and the read ZonedDateTime.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn zonedDateTime(@NotNull T t, @NotNull BiConsumer tZonedDateTime);

    /**
     * Reads a LocalDate from the wire and applies it to a given object using the provided BiConsumer.
     *
     * @param         The type of object to be passed to the BiConsumer.
     * @param t          The object to be passed to the BiConsumer.
     * @param tLocalDate The BiConsumer that accepts the object and the read LocalDate.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn date(@NotNull T t, @NotNull BiConsumer tLocalDate);

    /**
     * Reads a LocalDate directly from the wire.
     *
     * @return The LocalDate read from the wire.
     */
    default LocalDate date() {
        return WireInternal.intern(LocalDate.class, text());
    }

    /**
     * Reads a LocalTime directly from the wire.
     *
     * @return The LocalTime read from the wire.
     */
    default LocalTime time() {
        return WireInternal.intern(LocalTime.class, text());
    }

    /**
     * Reads a LocalDateTime directly from the wire.
     *
     * @return The LocalDateTime read from the wire.
     */
    default LocalDateTime dateTime() {
        return WireInternal.intern(LocalDateTime.class, text());
    }

    /**
     * Reads a ZonedDateTime directly from the wire.
     *
     * @return The ZonedDateTime read from the wire.
     */
    default ZonedDateTime zonedDateTime() {
        return WireInternal.intern(ZonedDateTime.class, text());
    }

    /**
     * Checks if there is another element to read in a sequence or collection.
     *
     * @return True if there is another element to read, false otherwise.
     */
    boolean hasNext();

    /**
     * Checks if there is another item in a sequence.
     *
     * @return True if there is another sequence item, false otherwise.
     */
    boolean hasNextSequenceItem();

    /**
     * Reads a UUID from the wire and applies it to a given object using the provided BiConsumer.
     *
     * @param    The type of object to be passed to the BiConsumer.
     * @param t     The object to be passed to the BiConsumer.
     * @param tuuid The BiConsumer that accepts the object and the read UUID.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn uuid(@NotNull T t, @NotNull BiConsumer tuuid);

    /**
     * Reads a LongArrayValues from the wire and applies it to a given object using the provided BiConsumer.
     *
     * @param     The type of object to be passed to the BiConsumer.
     * @param values The LongArrayValues to read the data into.
     * @param t      The object to be passed to the BiConsumer.
     * @param setter The BiConsumer that accepts the object and the LongArrayValues.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn int64array(@Nullable LongArrayValues values, T t, @NotNull BiConsumer setter);

    /**
     * Reads a 128-bit integer value from the wire into the specified TwoLongValue.
     *
     * @param value The TwoLongValue to read the 128-bit integer into.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default WireIn int128(@NotNull TwoLongValue value) {
        throw new UnsupportedOperationException();
    }

    /**
     * Reads a 64-bit integer value from the wire into the specified LongValue.
     *
     * @param value The LongValue to read the 64-bit integer into.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    WireIn int64(@NotNull LongValue value);

    /**
     * Reads a 32-bit integer value from the wire into the specified IntValue.
     *
     * @param value The IntValue to read the 32-bit integer into.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    WireIn int32(@NotNull IntValue value);

    /**
     * Reads a 64-bit integer for binding. If the provided LongValue is null, creates a new reference.
     *
     * @param value The LongValue to be populated or null.
     * @return The populated or newly created LongValue.
     */
    @NotNull
    default LongValue int64ForBinding(@Nullable LongValue value) {
        @NotNull LongValue ret = value == null ? wireIn().newLongReference() : value;
        int64(ret);
        return ret;
    }

    /**
     * Reads a boolean value and populates the provided BooleanValue.
     *
     * @param ret The BooleanValue to be populated.
     * @return The current WireIn instance.
     */
    WireIn bool(@NotNull BooleanValue ret);

    /**
     * Reads a 64-bit signed integer, populates the LongValue, and applies the LongValue using the provided consumer.
     *
     * @param value  The LongValue to be populated.
     * @param t      The target object.
     * @param setter The consumer that accepts the target object and the populated LongValue.
     * @param     The type of the target object.
     * @return The current WireIn instance.
     */
    @NotNull  WireIn int64(@Nullable LongValue value, T t, @NotNull BiConsumer setter);

    /**
     * Reads a 32-bit signed integer, populates the IntValue, and applies the IntValue using the provided consumer.
     *
     * @param value  The IntValue to be populated.
     * @param t      The target object.
     * @param setter The consumer that accepts the target object and the populated IntValue.
     * @param     The type of the target object.
     * @return The current WireIn instance.
     */
    @NotNull  WireIn int32(@Nullable IntValue value, T t, @NotNull BiConsumer setter);

    /**
     * Reads a sequence of values using the provided consumer.
     *
     * @param t       The target object.
     * @param tReader The consumer that reads the sequence into the target object.
     * @param      The type of the target object.
     * @return A boolean indicating if the sequence reading was successful.
     */
     boolean sequence(@NotNull T t, @NotNull BiConsumer tReader);

    /**
     * Processes a sequence of values from the wire, storing them in a list. It uses a buffer to minimize object creation.
     *
     * @param list      The list to store the processed items.
     * @param buffer    The buffer for reusing objects.
     * @param bufferAdd Supplier to provide new instances for the buffer.
     * @param reader0   The reader that processes each item in the sequence.
     * @return True if the sequence was processed, false otherwise.
     */
     boolean sequence(List list, @NotNull List buffer, Supplier bufferAdd, Reader reader0) throws InvalidMarshallableException;

    /**
     * Processes a sequence of values from the wire using a SerializationStrategy.
     *
     * @param      The type of the object to be processed.
     * @param t       The object to be processed.
     * @param tReader The SerializationStrategy to process the object.
     * @return True if the sequence was processed, false otherwise.
     */
    default  boolean sequence(@NotNull T t, @NotNull SerializationStrategy tReader) throws InvalidMarshallableException {
        return sequence(t, (using, in) -> tReader.readUsing(null, using, in, BracketType.UNKNOWN));
    }

    /**
     * Helper method to read a sequence of values into a list using a buffer.
     *
     * @param v         The ValueIn to read from.
     * @param list      The list to store the read values.
     * @param buffer    The buffer for reusing objects.
     * @param bufferAdd Supplier to provide new instances for the buffer.
     */
    default  void reader0(ValueIn v, List list, List buffer, Supplier bufferAdd) throws InvalidMarshallableException {
        while (v.hasNextSequenceItem()) {
            int size = list.size();
            if (buffer.size() <= size) {
                buffer.add(bufferAdd.get());
            }

            final T t = buffer.get(size);
            if (t instanceof Resettable) ((Resettable) t).reset();
            list.add((T) v.object(t, (Class) t.getClass()));
        }
    }

    /**
     * sequence to use when using a cached buffer
     *
     * @param list      of items to populate
     * @param buffer    of objects of the same type to reuse
     * @param bufferAdd supplier to call when the buffer needs extending
     * @return true if there is any data.
     */
    default  boolean sequence(@NotNull List list,
                                 @NotNull List buffer,
                                 @NotNull Supplier bufferAdd) throws InvalidMarshallableException {
        list.clear();
        return sequence(list, buffer, bufferAdd, this::reader0);
    }

    /**
     * Processes a sequence of values from the wire, applying a TriConsumer to each item in the sequence.
     *
     * @param      The type of the first object to be passed to the TriConsumer.
     * @param      The type of the second object to be passed to the TriConsumer.
     * @param t       The first object to be passed to the TriConsumer.
     * @param k       The second object to be passed to the TriConsumer.
     * @param tReader The TriConsumer that processes each item in the sequence.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  WireIn sequence(@NotNull T t, K k, @NotNull TriConsumer tReader) throws InvalidMarshallableException;

    /**
     * Reads a sequence of values and applies a function that returns the length of the sequence.
     *
     * @param t       The target object.
     * @param tReader A function that accepts a ValueIn reader and the target object and returns the length.
     * @param      The type of the target object.
     * @return The length of the sequence.
     */
    default  int sequenceWithLength(@NotNull T t, @NotNull ToIntBiFunction tReader) {
        int[] length = {0};
        sequence(t, (tt, in) -> length[0] = tReader.applyAsInt(in, tt));
        return length[0];
    }

    /**
     * Reads an array of Bytes objects from the wire, populating the provided array.
     *
     * @param array The array of Bytes objects to be populated.
     * @return The number of Bytes objects read and populated.
     */
    default int array(Bytes[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length) {
                if (a[i] == null)
                    a[i] = Bytes.allocateElasticOnHeap(32);
                bytes(a[i++]);
            }
            return i;
        });
    }

    /**
     * Reads an array of double values from the wire, populating the provided array.
     *
     * @param array The array of double values to be populated.
     * @return The number of double values read and populated.
     */
    default int array(double[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.float64();
            return i;
        });
    }

    /**
     * Reads an array of double values with delta compression from the wire, populating the provided array.
     *
     * @param array The array of double values to be populated.
     * @return The number of double values read and populated.
     */
    default int arrayDelta(double[] array) {
        return sequenceWithLength(array, (in, a) -> {
            if (!in.hasNextSequenceItem() || a.length == 0)
                return 0;
            double a0 = a[0] = in.float64();
            int i = 1;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.float64() + a0;
            return i;
        });
    }

    /**
     * Reads an array of boolean values from the wire, populating the provided array.
     *
     * @param array The array of boolean values to be populated.
     * @return The number of boolean values read and populated.
     */
    default int array(boolean[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.bool();
            return i;
        });
    }

    /**
     * Reads an array of long values from the wire, populating the provided array.
     *
     * @param array The array of long values to be populated.
     * @return The number of long values read and populated.
     */
    default int array(long[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.int64();
            return i;
        });
    }

    /**
     * Reads an array of long values with delta compression from the wire, populating the provided array.
     *
     * @param array The array of long values to be populated.
     * @return The number of long values read and populated.
     */
    default int arrayDelta(long[] array) {
        return sequenceWithLength(array, (in, a) -> {
            if (!in.hasNextSequenceItem() || a.length == 0)
                return 0;
            long a0 = a[0] = in.int64();
            int i = 1;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.int64() + a0;
            return i;
        });
    }

    /**
     * Reads an array of int values from the wire, populating the provided array.
     *
     * @param array The array of int values to be populated.
     * @return The number of int values read and populated.
     */
    default int array(int[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.int32();
            return i;
        });
    }

    /**
     * Reads an array of byte values from the wire, populating the provided array.
     *
     * @param array The array of byte values to be populated.
     * @return The number of byte values read and populated.
     */
    default int array(byte[] array) {
        return sequenceWithLength(array, (in, a) -> {
            int i = 0;
            while (in.hasNextSequenceItem() && i < a.length)
                a[i++] = in.int8();
            return i;
        });
    }

    /**
     * Reads a Set of objects of a specified type from the wire.
     *
     * @param  The type of objects in the Set.
     * @param t   The Class object representing the type T.
     * @return A Set containing objects of type T, or throws InvalidMarshallableException in case of an error.
     */
    default  Set set(Class t) throws InvalidMarshallableException {
        return collection(LinkedHashSet::new, t);
    }

    /**
     * Reads a List of objects of a specified type from the wire.
     *
     * @param  The type of objects in the List.
     * @param t   The Class object representing the type T.
     * @return A List containing objects of type T, or throws InvalidMarshallableException in case of an error.
     */
    default  List list(Class t) throws InvalidMarshallableException {
        return collection(ArrayList::new, t);
    }

    /**
     * Reads a Collection of objects of a specified type from the wire, using the provided supplier for the Collection type.
     *
     * @param       The type of objects in the Collection.
     * @param       The type of the Collection.
     * @param supplier A Supplier providing instances of the Collection type C.
     * @param t        The Class object representing the type T.
     * @return A Collection containing objects of type T, or throws InvalidMarshallableException in case of an error.
     */
    default > C collection(@NotNull Supplier supplier, Class t) throws InvalidMarshallableException {
        C list = supplier.get();
        sequence(list, t, (s, kls, v) -> {
            while (v.hasNextSequenceItem())
                s.add(v.object(kls));
        });
        return list;
    }

    /**
     * Reads a Set of ReadMarshallable objects from the wire, and applies them to a provided object using the function.
     *
     * @param        The type of the object to apply the Set to.
     * @param        The type of the ReadMarshallable objects.
     * @param o         The object to apply the Set to.
     * @param tSupplier A Function providing instances of type T.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default  WireIn set(@NotNull O o, Function tSupplier) throws InvalidMarshallableException {
        return collection(o, tSupplier);
    }

    /**
     * Reads a List of ReadMarshallable objects from the wire, and applies them to a provided object using the function.
     *
     * @param        The type of the object to apply the List to.
     * @param        The type of the ReadMarshallable objects.
     * @param o         The object to apply the List to.
     * @param tSupplier A Function providing instances of type T.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default  WireIn list(@NotNull O o, Function tSupplier) throws InvalidMarshallableException {
        return collection(o, tSupplier);
    }

    /**
     * Reads a sequence of {@link ReadMarshallable} items into a collection, where each item is constructed using the provided {@link Function}.
     *
     * @param o An object passed to the function to create instances of {@link ReadMarshallable}.
     * @param tSupplier A function that, given the object 'o', returns an instance of {@link ReadMarshallable}.
     * @param  The type of the provided object.
     * @param  The type of the ReadMarshallable.
     * @return The current {@link WireIn} instance for chaining.
     * @throws InvalidMarshallableException If there's a serialization issue.
     */
    @NotNull
    default  WireIn collection(@NotNull O o, Function tSupplier) throws InvalidMarshallableException {
        sequence(o, tSupplier, (o2, ts, v) -> {
            while (v.hasNextSequenceItem()) {
                T t = ts.apply(o2);
                v.marshallable(t);
            }
        });
        return wireIn();
    }

    /**
     * Reads a Map of marshallable key-value pairs as specified by the provided classes.
     *
     * @param     The type of keys in the Map.
     * @param     The type of values in the Map.
     * @param kClass The class of the keys.
     * @param vClass The class of the values.
     * @return A Map containing the key-value pairs, or null if the Map could not be read.
     * @throws InvalidMarshallableException if the key or value types are invalid
     */
    @Nullable
    default  Map marshallableAsMap(Class kClass, @NotNull Class vClass) throws InvalidMarshallableException {
        return marshallableAsMap(kClass, vClass, new LinkedHashMap<>());
    }

    /**
     * Reads a Map of marshallable key-value pairs into the provided Map.
     *
     * @param     The type of keys in the Map.
     * @param     The type of values in the Map.
     * @param kClass The class of the keys.
     * @param vClass The class of the values.
     * @param map    The Map to populate with the read key-value pairs.
     * @return The provided Map populated with key-value pairs, or null if the Map could not be read.
     */
    @Nullable
    default  Map marshallableAsMap(Class kClass, @NotNull Class vClass, @NotNull Map map) {
        return marshallable(m -> m.readAllAsMap(kClass, vClass, map)) ? map : null;
    }

    /**
     * Applies a Function to this ValueIn, interpreting it as a WireIn for a marshallable object.
     *
     * @param                 The type of the result from the Function.
     * @param marshallableReader The Function to apply to this ValueIn.
     * @return The result of applying the Function to this ValueIn, or null if it cannot be applied.
     */
    @Nullable  T applyToMarshallable(Function marshallableReader);

    /**
     * Reads a typed marshallable object from the wire.
     *
     * @return The marshallable object read from the wire, or null if it cannot be read.
     * @throws IORuntimeException           if an I/O error occurs
     * @throws InvalidMarshallableException if the marshallable object is invalid
     */
    @Nullable  T typedMarshallable() throws IORuntimeException, InvalidMarshallableException;

    /**
     * Reads a typed marshallable object from the wire, using the provided function to create instances.
     *
     * @param marshallableFunction The function to create marshallable object instances.
     * @return The marshallable object read from the wire, or null if it cannot be read.
     * @throws IORuntimeException           if an I/O error occurs
     * @throws InvalidMarshallableException if the marshallable object is invalid
     */
    @Nullable
    default  T typedMarshallable(@NotNull Function, ReadMarshallable> marshallableFunction)
            throws IORuntimeException, InvalidMarshallableException {
        @Nullable final Class aClass = (Class) typePrefix();

        if (ReadMarshallable.class.isAssignableFrom(aClass)) {
            final ReadMarshallable marshallable = marshallableFunction.apply(aClass);
            marshallable(marshallable);
            return (T) marshallable;
        }
        return object(null, aClass);
    }

    /**
     * Reads a type prefix and applies it to a given object using the provided BiConsumer.
     *
     * @param  The type of the object to apply the type prefix to.
     * @param t   The object to apply the type prefix to.
     * @param ts  The BiConsumer that accepts the object and the type prefix.
     * @return The WireIn instance for method chaining.
     */
    @NotNull  ValueIn typePrefix(T t, @NotNull BiConsumer ts);

    /**
     * Consumes a type literal (a class name) as text from the wire, passing it to a consumer.
     *
     * @param t The object to which the type literal relates.
     * @param classNameConsumer A consumer that accepts the provided object and the read class name.
     * @param  The type of the provided object.
     * @return The current {@link WireIn} instance for chaining.
     * @throws IORuntimeException If there's an IO issue during reading.
     * @throws BufferUnderflowException If there's not enough data in the buffer.
     */
    @NotNull  WireIn typeLiteralAsText(T t, @NotNull BiConsumer classNameConsumer)
            throws IORuntimeException, BufferUnderflowException;

    /**
     * Retrieves a {@link ClassLookup} instance associated with the current {@link WireIn}.
     * The ClassLookup allows for the resolution of class names to actual {@link Class} objects.
     *
     * @return The associated ClassLookup instance.
     */
    ClassLookup classLookup();

    /**
     * Reads a type literal as text and applies it to a given object using the provided BiConsumer.
     *
     * @param            The type of the object to apply the type literal to.
     * @param t             The object to apply the type literal to.
     * @param classConsumer The BiConsumer that accepts the object and the type literal.
     * @return The WireIn instance for method chaining.
     * @throws IORuntimeException       if an I/O error occurs
     * @throws BufferUnderflowException if the buffer underflows while reading
     */
    @NotNull
    default  WireIn typeLiteral(T t, @NotNull BiConsumer classConsumer) throws IORuntimeException {
        return typeLiteralAsText(t, (o, x) ->
                classConsumer.accept(o, classLookup().forName(x))
        );
    }

    /**
     * Reads a type literal from the wire, applies it to a given object using the provided BiConsumer, and uses a default Class if necessary.
     *
     * @param            The type of the object to apply the type literal to.
     * @param t             The object to apply the type literal to.
     * @param classConsumer The BiConsumer that accepts the object and the Class derived from the type literal.
     * @param defaultClass  The default Class to use if the type literal cannot be resolved.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default  WireIn typeLiteral(T t, @NotNull BiConsumer classConsumer, Class defaultClass) {
        return typeLiteralAsText(t, (o, x) -> {
            Class u = classLookup().forName(x);
            classConsumer.accept(o, u);
        });
    }

    /**
     * Reads a marshallable object from the wire and applies a specified SerializationStrategy.
     *
     * @param object   The object to populate with the marshallable data.
     * @param strategy The SerializationStrategy to use for reading the marshallable data.
     * @return The object populated with marshallable data, or null if it cannot be read.
     * @throws BufferUnderflowException     if the buffer underflows while reading
     * @throws IORuntimeException           if an I/O error occurs
     * @throws InvalidMarshallableException if the marshallable object is invalid
     */
    @Nullable
    Object marshallable(@NotNull Object object, @NotNull SerializationStrategy strategy)
            throws BufferUnderflowException, IORuntimeException, InvalidMarshallableException;

    /**
     * Reads a Serializable object from the wire.
     *
     * @param object The Serializable object to populate with the data.
     * @return True if the object was successfully read, false otherwise.
     * @throws BufferUnderflowException     if the buffer underflows while reading
     * @throws IORuntimeException           if an I/O error occurs
     * @throws InvalidMarshallableException if the Serializable object is invalid
     */
    default boolean marshallable(@NotNull Serializable object) throws BufferUnderflowException, IORuntimeException, InvalidMarshallableException {
        return marshallable(object, SerializationStrategies.SERIALIZABLE) != null;
    }

    /**
     * Reads a ReadMarshallable object from the wire.
     *
     * @param object The ReadMarshallable object to populate with the data.
     * @return True if the object was successfully read, false otherwise.
     * @throws BufferUnderflowException     if the buffer underflows while reading
     * @throws IORuntimeException           if an I/O error occurs
     * @throws InvalidMarshallableException if the ReadMarshallable object is invalid
     */
    default boolean marshallable(@NotNull ReadMarshallable object) throws BufferUnderflowException, IORuntimeException, InvalidMarshallableException {
        return marshallable(object, SerializationStrategies.MARSHALLABLE) != null;
    }

    /**
     * Reads a boolean value from the wire.
     *
     * @return The boolean value read from the wire.
     */
    boolean bool();

    /**
     * Reads an 8-bit integer (byte) value from the wire.
     *
     * @return The 8-bit integer value read from the wire.
     */
    byte int8();

    /**
     * Reads a 16-bit integer (short) value from the wire.
     *
     * @return The 16-bit integer value read from the wire.
     */
    short int16();

    /**
     * Reads an unsigned 16-bit integer (represented as an int) from the wire.
     *
     * @return The unsigned 16-bit integer value read from the wire.
     */
    int uint16();

    /**
     * Reads a 32-bit integer (int) value from the wire.
     *
     * @return The 32-bit integer value read from the wire.
     */
    int int32();

    /**
     * Reads a 32-bit integer (int) value from the wire with a previous value as a reference.
     *
     * @param previous The previous 32-bit integer value.
     * @return The 32-bit integer value read from the wire.
     */
    default int int32(int previous) {
        return int32();
    }

    /**
     * Reads a 64-bit integer (long) value from the wire.
     *
     * @return The 64-bit integer value read from the wire.
     */
    long int64();

    /**
     * Reads a 64-bit integer (long) value from the wire with a previous value as a reference.
     *
     * @param previous The previous 64-bit integer value.
     * @return The 64-bit integer value read from the wire.
     */
    default long int64(long previous) {
        return int64();
    }

    /**
     * Reads a 32-bit floating point number from the wire.
     *
     * @return The float value read from the wire.
     */
    float float32();

    /**
     * Reads a 32-bit floating-point (float) value from the wire with a previous value as a reference.
     *
     * @param previous The previous 32-bit floating-point value.
     * @return The 32-bit floating-point value read from the wire.
     */
    default float float32(float previous) {
        return float32();
    }

    /**
     * Reads a 64-bit floating point number from the wire.
     * If the data is not parsed successfully, returns -0.0.
     *
     * @return The double value read from the wire, or -0.0 if parsing fails.
     */
    double float64();

    /**
     * Reads a 64-bit floating-point (double) value from the wire with a previous value as a reference.
     *
     * @param previous The previous 64-bit floating-point value.
     * @return The 64-bit floating-point value read from the wire.
     */
    default double float64(double previous) {
        return float64();
    }

    /**
     * Reads a Class type literal from the wire.
     *
     * @return The Class corresponding to the type literal read from the wire, or null if it cannot be resolved.
     * @throws IORuntimeException       if an I/O error occurs
     * @throws BufferUnderflowException if the buffer underflows while reading
     */
    @Nullable
    default  Class typeLiteral() throws IORuntimeException, BufferUnderflowException {
        return (Class) typeLiteral((sb, e) -> {
            throw new IORuntimeException(e);
        });
    }

    /**
     * Reads a type literal from the wire, returning it as a Type object, with a fallback for unresolved types.
     *
     * @return The Type corresponding to the literal read from the wire, or a fallback unresolved type.
     * @throws IORuntimeException       if an I/O error occurs
     * @throws BufferUnderflowException if the buffer underflows while reading
     */
    @Nullable
    default Type lenientTypeLiteral() throws IORuntimeException, BufferUnderflowException {
        return typeLiteral((sb, e) -> UnresolvedType.of(sb.toString()));
    }

    /**
     * Reads a type literal from the wire, applying a handler for unresolved types.
     *
     * @param unresolvedHandler The handler to apply for unresolved types.
     * @return The Type corresponding to the literal read from the wire, or the result of the unresolved handler.
     */
    Type typeLiteral(BiFunction unresolvedHandler);

    /**
     * Reads a Throwable from the wire, optionally appending the current stack trace.
     *
     * @param appendCurrentStack True to append the current stack trace to the Throwable.
     * @return The Throwable read from the wire.
     * @throws InvalidMarshallableException if the Throwable object is invalid
     */
    default Throwable throwable(boolean appendCurrentStack) throws InvalidMarshallableException {
        return WireInternal.throwable(this, appendCurrentStack);
    }

    /**
     * Reads an Enum value of the specified type from the wire.
     *
     * @param eClass The class of the Enum type.
     * @return The Enum value read from the wire, or null if it cannot be read.
     */
    @Nullable
    default > E asEnum(Class eClass) {
        try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) {
            StringBuilder sb = stlSb.get();
            text(sb);
            return sb.length() == 0 ? null : WireInternal.internEnum(eClass, sb);
        }
    }

    /**
     * Reads an Enum value of the specified type from the wire and applies it to a Consumer.
     *
     * @param eClass    The class of the Enum type.
     * @param eConsumer The Consumer to apply the Enum value to.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default > WireIn asEnum(Class eClass, @NotNull Consumer eConsumer) {
        eConsumer.accept(asEnum(eClass));
        return wireIn();
    }

    /**
     * Reads an Enum value of the specified type from the wire and applies it to a given object using a BiConsumer.
     *
     * @param eClass     The class of the Enum type.
     * @param t          The object to apply the Enum value to.
     * @param teConsumer The BiConsumer that accepts the object and the Enum value.
     * @return The WireIn instance for method chaining.
     */
    @NotNull
    default , T> WireIn asEnum(Class eClass, T t, @NotNull BiConsumer teConsumer) {
        teConsumer.accept(t, asEnum(eClass));
        return wireIn();
    }

    /**
     * Reads an object of the specified class from the wire.
     *
     * @param clazz The class of the object to read.
     * @return The object read from the wire, or null if it cannot be read.
     * @throws InvalidMarshallableException if the object is invalid
     */
    @Nullable
    default  E object(@Nullable Class clazz) throws InvalidMarshallableException {
        return Wires.object0(this, null, clazz);
    }

    @Nullable
    default Object object() throws InvalidMarshallableException {
        @Nullable final Object o = objectWithInferredType(null, SerializationStrategies.ANY_OBJECT, null);
        return o;
    }

    /**
     * Deserializes an object from the current data stream, attempting to return any object that can be parsed.
     * 

* This method is used for logging purposes and aims to be lenient, capturing and returning exceptions * as results if they occur during the deserialization process. * * @return The deserialized object, or a {@link Throwable} if an error occurs during deserialization. */ default Object objectBestEffort() { ValidatableUtil.startValidateDisabled(); try { return object(); } catch (Throwable t) { return t; } finally { ValidatableUtil.endValidateDisabled(); } } /** * Reads an object from the wire. * * @param The type of the object to read. * @param using An instance of the object to reuse, or null to create a new instance. * @param clazz The class of the object to read. * @return The object read from the wire, or null if it cannot be read. * @throws InvalidMarshallableException if the object is invalid */ @Nullable default E object(@Nullable E using, @Nullable Class clazz) throws InvalidMarshallableException { E t; Object o = typePrefixOrObject(clazz); if (o == null && using instanceof ReadMarshallable) o = using; if (o != null && !(o instanceof Class)) { t = (@Nullable E) marshallable(o, MARSHALLABLE); } else { t = Wires.object2(this, using, clazz, true, (Class) o); } return ValidatableUtil.validate(t); } /** * Reads an object from the wire. * * @param The type of the object to read. * @param using An instance of the object to reuse, or null to create a new instance. * @param clazz The class of the object to read. * @param bestEffort Set to true for best effort reading, which may not throw exceptions for some errors. * @return The object read from the wire, or null if it cannot be read. * @throws InvalidMarshallableException if the object is invalid */ default E object(@Nullable E using, @Nullable Class clazz, boolean bestEffort) throws InvalidMarshallableException { E t = Wires.object1(this, using, clazz, bestEffort); return ValidatableUtil.validate(t); } /** * Gets the bracket type for the current value in the wire. * * @return The BracketType of the current value. */ @NotNull BracketType getBracketType(); /** * Checks if the current value in the wire is null. * * @return True if the current value is null, false otherwise. */ boolean isNull(); /** * Reads an object of a specified class from the wire and applies it to a given object using a BiConsumer. * * @param The type of the object to apply the read value to. * @param The type of the object being read. * @param clazz The class of the object being read. * @param t The object to apply the read value to. * @param e The BiConsumer that accepts the object and the read value. * @return The WireIn instance for method chaining. * @throws InvalidMarshallableException if the object is invalid */ @Nullable default WireIn object(@NotNull Class clazz, T t, @NotNull BiConsumer e) throws InvalidMarshallableException { e.accept(t, object(clazz)); return wireIn(); } /** * Checks if the current value in the wire is typed. * * @return True if the current value is typed, false otherwise. */ boolean isTyped(); /** * Reads the type prefix from the wire. * * @return The type prefix as a Class, or null if it cannot be read. */ @Nullable Class typePrefix(); /** * read a class with a super class or actual class as a hint * * @param tClass the super-class, or actual class to use * @return the class or an instance of an object to use. * @throws ClassNotFoundRuntimeException if the specific class couldn't be found. */ @Nullable default Object typePrefixOrObject(Class tClass) throws ClassNotFoundRuntimeException { return typePrefix(); } /** * Resets the internal state of this ValueIn. */ void resetState(); /** * Reads an object from the wire with an inferred type. * * @param using An instance of the object to reuse, or null to create a new instance. * @param strategy The SerializationStrategy to use for reading the object. * @param type The type of the object to read. * @return The object read from the wire, or null if it cannot be read. * @throws InvalidMarshallableException if the object is invalid */ @Nullable Object objectWithInferredType(Object using, SerializationStrategy strategy, Class type) throws InvalidMarshallableException; /** * Checks if a value is present in the data stream. * * @return True if a value is present, false otherwise. */ default boolean isPresent() { return true; } /** * Reads a UUID from the wire. * * @return The UUID read from the wire, or null if it cannot be read. */ @NotNull default UUID uuid() { return UUID.fromString(text()); } /** * Checks if the current value in the wire is binary. * * @return True if the current value is binary, false otherwise. */ default boolean isBinary() { return false; } /** * Reads a long value from the wire using a LongConverter. * * @param longConverter The LongConverter to use for reading the long value. * @return The long value read from the wire. */ default long readLong(LongConverter longConverter) { try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { StringBuilder sb = stlSb.get(); text(sb); return longConverter.parse(sb); } } /** * Reads a boolean value from the wire. * * @return The boolean value read from the wire. */ default boolean readBoolean() { return bool(); } /** * Reads a byte value from the wire. * * @return The byte value read from the wire. */ default byte readByte() { return int8(); } /** * Reads a char value from the wire. * * @return The char value read from the wire. */ default char readChar() { return (char) uint16(); } /** * Reads a short value from the wire. * * @return The short value read from the wire. */ default short readShort() { return int16(); } /** * Reads an int value from the wire. * * @return The int value read from the wire. */ default int readInt() { return int32(); } /** * Reads a long value from the wire. * * @return The long value read from the wire. */ default long readLong() { return int64(); } /** * Reads a float value from the wire. * * @return The float value read from the wire. */ default float readFloat() { return float32(); } /** * Reads a double value from the wire. * * @return The double value read from the wire. */ default double readDouble() { return float64(); } /** * Reads a String from the wire. * * @return The String read from the wire, or null if it cannot be read. */ default String readString() { return text(); } /** * Interface for reading values from the wire into a list. */ interface Reader { /** * Accepts and processes a value from the data stream, with the possibility of * utilizing provided lists and suppliers for custom data processing. * * @param The type of elements in the lists. * @param valueIn The input value from the data stream. * @param list A list to potentially store and process the data. * @param buffer An auxiliary buffer list for temporary storage and processing. * @param bufferAdd A supplier to generate elements for the buffer list. * @throws InvalidMarshallableException If an error occurs during the processing. */ void accept(ValueIn valueIn, List list, List buffer, Supplier bufferAdd) throws InvalidMarshallableException; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy