package com.oracle.svm.core.hub;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
public final class GenericInfo {
private static final TypeVariable<?>[] EMPTY_TYPE_VARIABLE_ARRAY = new TypeVariable<?>[0];
private static final GenericInfo EMPTY_GENERIC_INFO = new GenericInfo(EMPTY_TYPE_VARIABLE_ARRAY, null, null);
@Platforms(Platform.HOSTED_ONLY.class)
public static GenericInfo factory(TypeVariable<?>[] typeParameters, Type[] genericInterfaces, Type genericSuperClass) {
boolean hasTypeParameters = typeParameters.length > 0;
boolean hasGenericInterfaces = genericInterfaces.length > 0 && !Arrays.stream(genericInterfaces).allMatch(Class.class::isInstance);
boolean hasGenericSuperClass = genericSuperClass != null && !(genericSuperClass instanceof Class);
if (hasTypeParameters || hasGenericInterfaces || hasGenericSuperClass) {
return new GenericInfo(encodeTypeParameters(typeParameters), encodeGenericInterfaces(hasGenericInterfaces, genericInterfaces),
encodeGenericSuperClass(hasGenericSuperClass, genericSuperClass));
}
return EMPTY_GENERIC_INFO;
}
private static Object encodeTypeParameters(TypeVariable<?>[] typeParameters) {
if (typeParameters.length == 1) {
return typeParameters[0];
}
return typeParameters;
}
private static Object encodeGenericInterfaces(boolean hasGenericInterfaces, Type[] genericInterfaces) {
if (hasGenericInterfaces) {
if (genericInterfaces.length == 1) {
return genericInterfaces[0];
} else {
return genericInterfaces;
}
} else {
return null;
}
}
private static Type encodeGenericSuperClass(boolean hasGenericSuperClass, Type genericSuperClass) {
if (hasGenericSuperClass) {
return genericSuperClass;
}
return null;
}
private final Object typeParametersEncoding;
private final Object genericInterfacesEncoding;
private final Type genericSuperClass;
@Platforms(Platform.HOSTED_ONLY.class)
private GenericInfo(Object typeParameters, Object genericInterfaces, Type genericSuperClass) {
assert typeParameters != null;
this.typeParametersEncoding = typeParameters;
this.genericInterfacesEncoding = genericInterfaces;
this.genericSuperClass = genericSuperClass;
}
TypeVariable<?>[] getTypeParameters() {
if (typeParametersEncoding instanceof Type) {
return new TypeVariable<?>[]{(TypeVariable<?>) typeParametersEncoding};
} else {
return ((TypeVariable<?>[]) typeParametersEncoding).clone();
}
}
boolean hasGenericInterfaces() {
return genericInterfacesEncoding != null;
}
Type[] getGenericInterfaces() {
assert hasGenericInterfaces();
if (genericInterfacesEncoding instanceof Type) {
return new Type[]{(Type) genericInterfacesEncoding};
} else {
return ((Type[]) genericInterfacesEncoding).clone();
}
}
boolean hasGenericSuperClass() {
return genericSuperClass != null;
}
Type getGenericSuperClass() {
assert hasGenericSuperClass();
return genericSuperClass;
}
}