All Downloads are FREE. Search and download functionalities are using the official Maven repository.

foundation.icon.ee.util.Shadower Maven / Gradle / Ivy

There is a newer version: 0.9.6
Show newest version
package foundation.icon.ee.util;

import foundation.icon.ee.struct.Property;
import foundation.icon.ee.types.Address;
import i.IObject;
import i.IObjectArray;
import i.RuntimeAssertionError;
import pi.UnmodifiableArrayList;
import pi.UnmodifiableArrayMap;

import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.util.Map;

public class Shadower {
    /**
     * Shadows internal objects according to a shadow class.
     *
     * @param obj internal object. Map, array, byte[], Address, String, Boolean,
     *            BigInteger.
     * @param c   shadow class
     * @param  shadow class
     * @return shadow object
     * @throws IllegalArgumentException thrown if obj and c does not match
     *                                  correctly or obj is not a valid parameter/return object or c is
     *                                  not a valid parameter/return class.
     */
    public static  T shadow(Object obj, Class c) {
        @SuppressWarnings("unchecked")
        T res = (T) shadowImpl(obj, c);
        return res;
    }

    // throws IllegalArgumentException
    public static Object[] shadowObjects(Object[] objs, Class[] c) {
        if (objs.length != c.length) {
            throw new IllegalArgumentException();
        }
        var res = new Object[objs.length];
        for (int i = 0; i < objs.length; ++i) {
            res[i] = shadowImpl(objs[i], c[i]);
        }
        return res;
    }

    public static  U shadowReturnValue(Object obj, Class c) {
        if (obj == null) {
            return null;
        } else if (c.isPrimitive()) {
            @SuppressWarnings("unchecked")
            U res = (U) shadowPrimitiveReturnValue(obj, c);
            return res;
        }
        @SuppressWarnings("unchecked")
        U res = (U) shadowImpl(obj, c);
        return res;
    }

    private static i.IObjectArray newObjectArray(Class c, int l) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        var post = c.getName().substring(2);
        int i = 0;
        for (; i < post.length(); ++i) {
            if (post.charAt(i) != '_') {
                break;
            }
        }
        post = post.substring(i); // skip _
        var aName = "a." + "$".repeat(i) + post;
        Class aClass = null;
        aClass = c.getClassLoader().loadClass(aName);
        var m = aClass.getMethod("initArray", int.class);
        return (i.IObjectArray) m.invoke(null, l);
    }

    // called only for ObjectArray
    private static Class getElementClass(Class cls) throws ClassNotFoundException {
        // a.$$I : int[][]
        // w.__Lu.user.Class : interface for u.user.Class[][]
        // a.$$Lu.user.Class : class for u.user.Class[][]
        var elem = cls.getName().substring(3);
        if (elem.startsWith("$")) {
            switch (elem) {
                case "$Z":
                    return a.BooleanArray.class;
                case "$C":
                    return a.CharArray.class;
                case "$B":
                    return a.ByteArray.class;
                case "$S":
                    return a.ShortArray.class;
                case "$I":
                    return a.IntArray.class;
                case "$J":
                    return a.LongArray.class;
            }
            elem = "a.$" + elem.substring(1);
        } else if (elem.startsWith("_")) {
            elem = "w._" + elem.substring(1);
        } else {
            // starts with 'L'
            elem = elem.substring(1);
        }
        return cls.getClassLoader().loadClass(elem);
    }

    private static Object shadowImpl(Object obj, Class c) {
        try {
            return _shadow(obj, c);
        } catch (ClassCastException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private static IObject shadowPrimitiveReturnValue(Object obj, Class c) {
        if (c == boolean.class) {
            return s.java.lang.Boolean.avm_valueOf((Boolean) obj);
        } else if(c == char.class) {
            return s.java.lang.Character.avm_valueOf(
                    (char)((BigInteger)obj).intValue());
        } else if(c == byte.class) {
            return s.java.lang.Byte.avm_valueOf(((BigInteger)obj).byteValue());
        } else if(c == short.class) {
            return s.java.lang.Short.avm_valueOf(((BigInteger)obj).shortValue());
        } else if(c == int.class) {
            return s.java.lang.Integer.avm_valueOf(((BigInteger)obj).intValue());
        } else if(c == long.class) {
            return s.java.lang.Long.avm_valueOf(((BigInteger)obj).longValue());
        }
        return null;
    }

    private static Object _shadow(Object obj, Class c) {
        if (obj == null) {
            return null;
        } else if (c == boolean.class) {
            return obj;
        } else if (c == char.class) {
            return (char) ((BigInteger) obj).intValue();
        } else if (c == byte.class) {
            return ((BigInteger) obj).byteValue();
        } else if (c == short.class) {
            return ((BigInteger) obj).shortValue();
        } else if (c == int.class) {
            return ((BigInteger) obj).intValue();
        } else if (c == long.class) {
            return ((BigInteger) obj).longValue();
        } else if (c == s.java.lang.Boolean.class) {
            return s.java.lang.Boolean.avm_valueOf((Boolean) obj);
        } else if (c == s.java.lang.Character.class) {
            return s.java.lang.Character.avm_valueOf(
                    (char)((BigInteger)obj).intValue());
        } else if (c == s.java.lang.Byte.class) {
            return s.java.lang.Byte.avm_valueOf(((BigInteger)obj).byteValue());
        } else if (c == s.java.lang.Short.class) {
            return s.java.lang.Short.avm_valueOf(((BigInteger)obj).shortValue());
        } else if (c == s.java.lang.Integer.class) {
            return s.java.lang.Integer.avm_valueOf(((BigInteger)obj).intValue());
        } else if (c == s.java.lang.Long.class) {
            return s.java.lang.Long.avm_valueOf(((BigInteger)obj).longValue());
        } else if (c == s.java.math.BigInteger.class) {
            return s.java.math.BigInteger.newWithCharge((BigInteger)obj);
        } else if (c == s.java.lang.String.class) {
            return s.java.lang.String.newWithCharge((String)obj);
        } else if (c == p.score.Address.class) {
            return p.score.Address.newWithCharge(((Address)obj).toByteArray());
        } else if (c == a.BooleanArray.class) {
            var o = (Object[]) obj;
            var res = a.BooleanArray.initArray(o.length);
            for (int i=0; i elemClass = null;
            try {
                elemClass = getElementClass(c);
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException(e);
            }
            for (int i = 0; i < o.length; ++i) {
                res.set(i, _shadow(o[i], elemClass));
            }
            return res;
        } else if (c == s.java.util.List.class) {
            var o = (Object[]) obj;
            var sa = new IObject[o.length];
            int i = 0;
            for (var e : o) {
                sa[i++] = shadow(e);
            }
            return new UnmodifiableArrayList<>(sa);
        } else if (c == s.java.util.Map.class) {
            var o = (Map) obj;
            var skv = new IObject[o.size() * 2];
            int i = 0;
            for (var e : o.entrySet()) {
                skv[i++] = shadow(e.getKey());
                skv[i++] = shadow(e.getValue());
            }
            return new UnmodifiableArrayMap<>(skv);
        } else {
            // this must be a writable struct
            try {
                @SuppressWarnings("unchecked")
                var o = (Map) obj;
                var ctor = c.getConstructor();
                var res = ctor.newInstance();
                for (var e : o.entrySet()) {
                    var wp = Property.getWritableProperty(c, e.getKey());
                    if (wp == null) {
                        throw new IllegalArgumentException();
                    }
                    wp.set(res, _shadow(e.getValue(), wp.getType()));
                }
                return res;
            } catch (NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException e) {
                throw new IllegalArgumentException();
            }
        }
    }

    /**
     * Shadows internal objects.
     * @param obj internal object
     * @return shadow object
     */
    public static s.java.lang.Object shadow(Object obj) {
        if (obj==null) {
            return null;
        } else if (obj instanceof Boolean) {
            return s.java.lang.Boolean.avm_valueOf((Boolean) obj);
        } else if (obj instanceof BigInteger) {
            return s.java.math.BigInteger.newWithCharge((BigInteger)obj);
        } else if (obj instanceof String) {
            return s.java.lang.String.newWithCharge((String)obj);
        } else if (obj instanceof byte[]) {
            return a.ByteArray.newWithCharge((byte[])obj);
        } else if (obj instanceof Address) {
            return p.score.Address.newWithCharge(((Address)obj).toByteArray());
        } else if (obj instanceof Object[]) {
            var o = (Object[]) obj;
            var sa = new IObject[o.length];
            int i = 0;
            for (var e : o) {
                sa[i++] = Shadower.shadow(e);
            }
            return new UnmodifiableArrayList<>(sa);
        } else if (obj instanceof Map) {
            var o = (Map) obj;
            var skv = new IObject[o.size() * 2];
            int i = 0;
            for (Map.Entry e : o.entrySet()) {
                skv[i++] = shadow(e.getKey());
                skv[i++] = shadow(e.getValue());
            }
            return new UnmodifiableArrayMap<>(skv);
        } else {
            RuntimeAssertionError.unreachable("invalid shadow type");
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy