VariantEncoder.java
/*
* SPDX-FileCopyrightText: 2023-2025 Lucimber UG
* SPDX-License-Identifier: Apache-2.0
*/
package com.lucimber.dbus.codec.encoder;
import com.lucimber.dbus.type.DBusBasicType;
import com.lucimber.dbus.type.DBusContainerType;
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.nio.ByteOrder;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An encoder which encodes a variant to the D-Bus marshalling format using ByteBuffer.
*
* @see Encoder
* @see DBusVariant
*/
public final class VariantEncoder implements Encoder<DBusVariant, ByteBuffer> {
private static final Logger LOGGER = LoggerFactory.getLogger(VariantEncoder.class);
private final ByteOrder order;
/**
* Constructs a new instance with mandatory parameter.
*
* @param order the byte order of the produced bytes.
*/
public VariantEncoder(ByteOrder order) {
this.order = Objects.requireNonNull(order, "order must not be null");
}
@Override
public EncoderResult<ByteBuffer> encode(DBusVariant variant, int offset)
throws EncoderException {
Objects.requireNonNull(variant, "variant must not be null");
try {
int producedBytes = 0;
ByteBuffer output;
// Encode signature
DBusSignature contentSignature = determineContentSignature(variant.getDelegate());
Encoder<DBusSignature, ByteBuffer> sigEncoder = new SignatureEncoder();
EncoderResult<ByteBuffer> sigResult = sigEncoder.encode(contentSignature, offset);
final ByteBuffer sigBuffer = sigResult.getBuffer();
producedBytes += sigResult.getProducedBytes();
// Encode value
DBusType value = variant.getDelegate();
int valueOffset = offset + producedBytes;
EncoderResult<ByteBuffer> valueResult = EncoderUtils.encode(value, valueOffset, order);
final ByteBuffer valueBuffer = valueResult.getBuffer();
producedBytes += valueResult.getProducedBytes();
// Combine buffers
output = ByteBuffer.allocate(producedBytes);
output.put(sigBuffer);
output.put(valueBuffer);
output.flip();
EncoderResult<ByteBuffer> result = new EncoderResultImpl<>(producedBytes, output);
LOGGER.debug(
LoggerUtils.MARSHALLING,
"VARIANT: {}; Offset: {}; Padding: {}; Produced bytes: {};",
variant,
offset,
0,
producedBytes);
return result;
} catch (Exception ex) {
throw new EncoderException("Could not encode VARIANT.", ex);
}
}
private DBusSignature determineContentSignature(DBusType content) throws Exception {
if (content instanceof DBusBasicType) {
return DBusSignature.valueOf(String.valueOf(content.getType().getCode().getChar()));
} else if (content instanceof DBusContainerType containerType) {
return containerType.getSignature();
} else {
throw new Exception("Cannot determine content signature");
}
}
}