package openmods.serializable.providers;
import com.google.common.reflect.TypeToken;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Array;
import openmods.serializable.ISerializerProvider;
import openmods.serializable.SerializerRegistry;
import openmods.utils.ByteUtils;
import openmods.utils.io.IStreamSerializer;
public class ArraySerializerProvider implements ISerializerProvider {
@Override
public IStreamSerializer<?> getSerializer(Class<?> cls) {
if (cls.isArray()) {
final TypeToken<?> componentCls = TypeToken.of(cls).getComponentType();
return componentCls.isPrimitive()
? createPrimitiveSerializer(componentCls)
: createNullableSerializer(componentCls);
}
return null;
}
private static IStreamSerializer<?> createPrimitiveSerializer(final TypeToken<?> componentType) {
final IStreamSerializer<Object> componentSerializer = SerializerRegistry.instance.findSerializer(componentType.getType());
final Class<?> componentCls = componentType.getRawType();
return new IStreamSerializer<Object>() {
@Override
public Object readFromStream(DataInput input) throws IOException {
final int length = ByteUtils.readVLI(input);
Object result = Array.newInstance(componentCls, length);
for (int i = 0; i < length; i++) {
final Object value = componentSerializer.readFromStream(input);
Array.set(result, i, value);
}
return result;
}
@Override
public void writeToStream(Object o, DataOutput output) throws IOException {
final int length = Array.getLength(o);
ByteUtils.writeVLI(output, length);
for (int i = 0; i < length; i++) {
Object value = Array.get(o, i);
componentSerializer.writeToStream(value, output);
}
}
};
}
private static IStreamSerializer<?> createNullableSerializer(final TypeToken<?> componentType) {
return new NullableCollectionSerializer<Object>(componentType) {
@Override
protected Object createCollection(TypeToken<?> componentCls, int length) {
return Array.newInstance(componentCls.getRawType(), length);
}
@Override
protected int getLength(Object collection) {
return Array.getLength(collection);
}
@Override
protected Object getElement(Object collection, int index) {
return Array.get(collection, index);
}
@Override
protected void setElement(Object collection, int index, Object value) {
Array.set(collection, index, value);
}
};
}
}