VariantDecoder.java

/*
 * SPDX-FileCopyrightText: 2023-2025 Lucimber UG
 * SPDX-License-Identifier: Apache-2.0
 */
package com.lucimber.dbus.codec.decoder;

import com.lucimber.dbus.type.DBusSignature;
import com.lucimber.dbus.type.DBusType;
import com.lucimber.dbus.type.DBusVariant;
import com.lucimber.dbus.util.LoggerUtils;
import java.nio.ByteBuffer;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A decoder which unmarshals a variant from the byte stream format used by D-Bus.
 *
 * @see Decoder
 * @see DBusVariant
 */
public final class VariantDecoder implements Decoder<ByteBuffer, DBusVariant> {

    private static final Logger LOGGER = LoggerFactory.getLogger(VariantDecoder.class);

    @Override
    public DecoderResult<DBusVariant> decode(ByteBuffer buffer, int offset)
            throws DecoderException {
        Objects.requireNonNull(buffer, "buffer must not be null");

        try {
            int consumedBytes = 0;

            // Decode the signature
            Decoder<ByteBuffer, DBusSignature> signatureDecoder = new SignatureDecoder();
            DecoderResult<DBusSignature> sigResult = signatureDecoder.decode(buffer, offset);
            DBusSignature signature = sigResult.getValue();
            consumedBytes += sigResult.getConsumedBytes();

            if (signature.getQuantity() != 1) {
                throw new DecoderException("Signature must be a single complete type.");
            }

            // Decode the value with that signature
            int valueOffset = offset + consumedBytes;
            DecoderResult<? extends DBusType> valueResult =
                    DecoderUtils.decode(signature, buffer, valueOffset);
            consumedBytes += valueResult.getConsumedBytes();

            DBusVariant variant = DBusVariant.valueOf(valueResult.getValue());
            DecoderResult<DBusVariant> result = new DecoderResultImpl<>(consumedBytes, variant);

            LOGGER.debug(
                    LoggerUtils.MARSHALLING,
                    "VARIANT: {}; Offset: {}; Padding: {}; Consumed bytes: {};",
                    variant,
                    offset,
                    0,
                    consumedBytes);

            return result;
        } catch (Exception e) {
            throw new DecoderException("Could not decode VARIANT.", e);
        }
    }
}