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

overrun.marshal.Unmarshal Maven / Gradle / Ivy

There is a newer version: 0.1.0-alpha.34-jdk23
Show newest version
/*
 * MIT License
 *
 * Copyright (c) 2024 Overrun Organization
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 */

package overrun.marshal;

import org.jetbrains.annotations.Nullable;

import java.lang.foreign.AddressLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.VarHandle;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.function.Function;
import java.util.function.IntFunction;

import static java.lang.foreign.ValueLayout.*;

/**
 * C-to-Java helper.
 *
 * @author squid233
 * @since 0.1.0
 */
public final class Unmarshal {
    /**
     * The max string size.
     */
    public static final long STR_SIZE = Integer.MAX_VALUE - 8;
    /**
     * The address layout which dereferences a string with {@linkplain #STR_SIZE the max size}.
     */
    public static final AddressLayout STR_LAYOUT = ADDRESS.withTargetLayout(
        MemoryLayout.sequenceLayout(STR_SIZE, JAVA_BYTE)
    );
    private static final VarHandle vh_stringArray = Marshal.arrayVarHandle(STR_LAYOUT);

    private Unmarshal() {
    }

    /**
     * {@return {@code true} if the given segment is a null pointer; {@code false} otherwise}
     *
     * @param segment the native segment
     */
    public static boolean isNullPointer(@Nullable MemorySegment segment) {
        return segment == null || segment.equals(MemorySegment.NULL);
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(char v) {
        return v != 0;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(byte v) {
        return v != 0;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(short v) {
        return v != 0;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(int v) {
        return v != 0;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(long v) {
        return v != 0L;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(float v) {
        return (int) v != 0;
    }

    /**
     * Converts the given value to {@code boolean}.
     *
     * @param v the value
     * @return the {@code boolean} value
     */
    public static boolean unmarshalAsBoolean(double v) {
        return (int) v != 0;
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment
     * @return the string
     */
    public static @Nullable String unmarshalAsString(MemorySegment segment) {
        return unmarshalAsString(segment, StandardCharsets.UTF_8);
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment
     * @param charset the charset
     * @return the string
     */
    public static @Nullable String unmarshalAsString(MemorySegment segment, Charset charset) {
        return isNullPointer(segment) ? null : segment.getString(0L, charset);
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment, which size is unknown
     * @return the string
     */
    public static @Nullable String unboundString(MemorySegment segment) {
        return unboundString(segment, StandardCharsets.UTF_8);
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment, which size is unknown
     * @param charset the charset
     * @return the string
     */
    public static @Nullable String unboundString(MemorySegment segment, Charset charset) {
        return isNullPointer(segment) ? null : segment.reinterpret(STR_SIZE).getString(0L, charset);
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment which is pointer to a string
     * @return the string
     */
    public static @Nullable String unmarshalStringPointer(MemorySegment segment) {
        return unmarshalStringPointer(segment, StandardCharsets.UTF_8);
    }

    /**
     * Unmarshal the given segment as a string.
     *
     * @param segment the segment which is pointer to a string
     * @param charset the charset
     * @return the string
     */
    public static @Nullable String unmarshalStringPointer(MemorySegment segment, Charset charset) {
        return isNullPointer(segment) ? null : unmarshalAsString(segment.get(STR_LAYOUT, 0L), charset);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static boolean @Nullable [] unmarshal(OfBoolean elementLayout, MemorySegment segment) {
        if (isNullPointer(segment)) return null;
        final boolean[] arr = new boolean[checkArraySize(boolean[].class.getSimpleName(), segment.byteSize(), (int) elementLayout.byteSize())];
        for (int i = 0, l = arr.length; i < l; i++) {
            arr[i] = (boolean) Marshal.vh_booleanArray.get(segment, (long) i);
        }
        return arr;
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static char @Nullable [] unmarshal(OfChar elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static byte @Nullable [] unmarshal(OfByte elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static short @Nullable [] unmarshal(OfShort elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static int @Nullable [] unmarshal(OfInt elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static long @Nullable [] unmarshal(OfLong elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static float @Nullable [] unmarshal(OfFloat elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static double @Nullable [] unmarshal(OfDouble elementLayout, MemorySegment segment) {
        return isNullPointer(segment) ? null : segment.toArray(elementLayout);
    }


    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static boolean @Nullable [] unmarshalAsBooleanArray(MemorySegment segment) {
        return unmarshal(JAVA_BOOLEAN, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static char @Nullable [] unmarshalAsCharArray(MemorySegment segment) {
        return unmarshal(JAVA_CHAR, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static byte @Nullable [] unmarshalAsByteArray(MemorySegment segment) {
        return unmarshal(JAVA_BYTE, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static short @Nullable [] unmarshalAsShortArray(MemorySegment segment) {
        return unmarshal(JAVA_SHORT, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static int @Nullable [] unmarshalAsIntArray(MemorySegment segment) {
        return unmarshal(JAVA_INT, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static long @Nullable [] unmarshalAsLongArray(MemorySegment segment) {
        return unmarshal(JAVA_LONG, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static float @Nullable [] unmarshalAsFloatArray(MemorySegment segment) {
        return unmarshal(JAVA_FLOAT, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static double @Nullable [] unmarshalAsDoubleArray(MemorySegment segment) {
        return unmarshal(JAVA_DOUBLE, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @param generator     a function which produces a new array of the desired type and the provided length
     * @param function      a function to apply to each element. the argument of the function is a slice of {@code segment}
     * @param            the type of the element
     * @return the array
     */
    public static  T @Nullable [] unmarshal(MemoryLayout elementLayout, MemorySegment segment, IntFunction generator, Function function) {
        return isNullPointer(segment) ? null : segment.elements(elementLayout).map(function).toArray(generator);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static MemorySegment @Nullable [] unmarshal(AddressLayout elementLayout, MemorySegment segment) {
        return unmarshal(elementLayout, segment, MemorySegment[]::new, s -> s.get(ADDRESS, 0L));
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static MemorySegment @Nullable [] unmarshalAsAddressArray(MemorySegment segment) {
        return unmarshal(ADDRESS, segment);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @return the array
     */
    public static String @Nullable [] unmarshalAsStringArray(AddressLayout elementLayout, MemorySegment segment) {
        return unmarshalAsStringArray(elementLayout, segment, StandardCharsets.UTF_8);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param elementLayout the source element layout
     * @param segment       the segment
     * @param charset       the charset
     * @return the array
     */
    public static String @Nullable [] unmarshalAsStringArray(AddressLayout elementLayout, MemorySegment segment, Charset charset) {
        return unmarshal(elementLayout, segment, String[]::new, s -> s.get(STR_LAYOUT, 0L).getString(0L, charset));
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @return the array
     */
    public static String @Nullable [] unmarshalAsStringArray(MemorySegment segment) {
        return unmarshalAsStringArray(segment, StandardCharsets.UTF_8);
    }

    /**
     * Unmarshal the given segment as an array.
     *
     * @param segment the segment
     * @param charset the charset
     * @return the array
     */
    public static String @Nullable [] unmarshalAsStringArray(MemorySegment segment, Charset charset) {
        return unmarshalAsStringArray(ADDRESS, segment, charset);
    }

    private static int checkArraySize(String typeName, long byteSize, int elemSize) {
        if (!((byteSize & (elemSize - 1)) == 0)) {
            throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, byteSize));
        }
        long arraySize = byteSize / elemSize;
        if (arraySize > (Integer.MAX_VALUE - 8)) {
            throw new IllegalStateException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, byteSize));
        }
        return (int) arraySize;
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, boolean @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        for (int i = 0; i < dst.length; i++) {
            dst[i] = (boolean) Marshal.vh_booleanArray.get(src, (long) i);
        }
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, char @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_CHAR, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, byte @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_BYTE, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, short @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_SHORT, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, int @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_INT, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, long @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_LONG, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, float @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_FLOAT, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, double @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        MemorySegment.copy(src, JAVA_DOUBLE, 0L, dst, 0, dst.length);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, String @Nullable [] dst) {
        copy(src, dst, StandardCharsets.UTF_8);
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src     the source segment
     * @param dst     the destination
     * @param charset the charset
     */
    public static void copy(MemorySegment src, String @Nullable [] dst, Charset charset) {
        if (isNullPointer(src) || dst == null) return;
        for (int i = 0; i < dst.length; i++) {
            dst[i] = ((MemorySegment) vh_stringArray.get(src, (long) i)).getString(0L, charset);
        }
    }

    /**
     * Copies from the given segment to the destination.
     *
     * @param src the source segment
     * @param dst the destination
     */
    public static void copy(MemorySegment src, MemorySegment @Nullable [] dst) {
        if (isNullPointer(src) || dst == null) return;
        for (int i = 0; i < dst.length; i++) {
            dst[i] = ((MemorySegment) Marshal.vh_addressArray.get(src, (long) i));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy