package xapi.fu;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* Jutsu: technique, method, spell, skill or trick.
* Fujutsu: witchcraft.
*
* This package protected class is where any platform-specific magic needs to go,
* so you can hide things that are not supported on your platform.
*
* In order to implement your own Jutsu, you need to look inside the source file of {@link X_Fu},
* in particular, the package local class {@link Fu}.
*
* If you create a copy of this class, along with the {@link Fu#jutsu} field,
* then everywhere in xapi.fu will use your copy of these "magic operations".
*
* @author James X. Nelson (james@wetheinter.net)
* Created on 07/11/15.
*/
interface Jutsu {
default <T> T[] emptyArray(T[] notCopied, int length) {
Object arr = Array.newInstance(notCopied.getClass().getComponentType(), length);
return (T[]) arr;
}
default <T> T[] arrayCopy(T[] copied, int length) {
T[] arr = emptyArray(copied, length);
System.arraycopy(copied, 0, arr, 0, Math.min(length, copied.length));
return arr;
}
default int getLength(Object obj) {
return Array.getLength(obj);
}
default void setValue(Object obj, int index, Object value) {
Array.set(obj, index, value);
}
default Object getValue(Object obj, int index) {
return Array.get(obj, index);
}
default int applyArguments(int i, Many<HasInput> each, Object ... args) {
for (HasInput in : each) {
i = in.accept(i, args);
}
return i;
}
default <T> T[] pushCopy(T[] ts, T t) {
T[] result = Fu.jutsu.emptyArray(ts, ts.length + 1);
System.arraycopy(ts, 0, result, 0, ts.length);
result[ts.length] = t;
return result;
}
// By default, we always return clones. Enviros like Gwt can opt to reuse / mutate the array.
default <T> T[] pushOnto(T[] ts, T t) {
return pushCopy(ts, t);
}
default String lambdaName(Object o) {
final Class<?> c = o.getClass();
Method replaceMethod;
try {
replaceMethod = c.getDeclaredMethod("writeReplace");
} catch (NoSuchMethodException e) {
return null;
}
replaceMethod.setAccessible(true);
Object lambda;
try {
lambda = replaceMethod.invoke(o);
// the name of the generated lambda method is the perfect identifier for our lambda handlers :-)
Class l = Class.forName("java.lang.invoke.SerializedLambda");
Method m = l.getMethod("getImplMethodName");
String name = (String)m.invoke(lambda);
if (Boolean.parseBoolean(System.getProperty("xapi.debug", "false")) || !name.contains("lambda")){
m = l.getMethod("getFunctionalInterfaceClass");
name = m.invoke(lambda)+ "#" + name;
m = l.getMethod("getFunctionalInterfaceMethodSignature");
name = name + m.invoke(lambda);
}
m = l.getMethod("getCapturedArgCount");
int i = (Integer)m.invoke(lambda);
m = l.getMethod("getCapturedArg", int.class);
while(i --> 0) {
name += "|" + System.identityHashCode(m.invoke(lambda, i));
}
return name;
} catch (Exception ignored) {
ignored.printStackTrace();
}
return null;
}
default Type[] getGenericInterfaces(Class<?> c) {
return new Type[0];
}
}