/** * Generates a metatable containing metafunctions for a given object type using the currently * registered {@link LuaObjectMeta}s. * * <p>This method will only generate one metatable per class type; the mapping of already made * metatables will not be cleared at any point during runtime. If a metatable had already been * generated, that metatable is returned. * * <p>It is possible for functions within each object meta to override each other when this method * generates a new metatable. * * <p>If there are no suitable meta objects for the provided object or none of the applicable meta * objects have any metafunctions to register, null is returned. * * @param obj the Object to generate a metatable for * @return the metatable for the given Object */ public static LuaTable generateMetatable(Object obj) { LuaTable copyTable = Lua.METATABLES.get(obj.getClass()); if (copyTable == null && copyTable != Lua.EMPTY_METATABLE) { LuaTable functable = new LuaTable(); Lua.metas.clear(); Lua.META.values().forEach(Lua.metas::add); Lua.PMETA.values().forEach(Lua.metas::add); Lua.metas.forEach( meta -> { if (meta.getTargetObjectClass().isInstance(obj) && meta.getMetatable() != null) { LuaUtil.iterateTable( meta.getMetatable(), vargs -> { functable.set(vargs.arg(1), vargs.arg(2)); }); } }); Lua.metas.forEach( meta -> { meta.postMetaInit(functable); }); if (LuaUtil.getTableSize(functable) > 0) { LuaTable metatable = new LuaTable(); // add the object's metatable functions metatable.set("__index", functable); // add the stuff we do for every metatable GLOBAL_METATABLE .entries() .forEach( entry -> { metatable.set(entry.key, entry.value); }); Lua.METATABLES.put(obj.getClass(), metatable); copyTable = metatable; } else { Lua.METATABLES.put(obj.getClass(), Lua.EMPTY_METATABLE); } } if (copyTable != null && copyTable != Lua.EMPTY_METATABLE) { return LuaUtil.copyTable(copyTable, true); } return null; }
/** * Internal method. * * <p>Returns a stored {@link LuaObjectMeta} instance. */ static LuaObjectMeta getMeta(Class<? extends LuaObjectMeta> metaClass) { for (LuaObjectMeta meta : Lua.PMETA.values()) { if (meta.getClass() == metaClass) { return meta; } } for (LuaObjectMeta meta : Lua.META.values()) { if (meta.getClass() == metaClass) { return meta; } } return null; }
/** * Returns the {@link LuaObjectMeta} registered with the provided typename. * * @param metaName the typename to match * @return the LuaObjectMeta matching the given typename, or null if doesn't exist */ public static LuaObjectMeta getMeta(String metaName) { for (LuaObjectMeta meta : Lua.PMETA.values()) { if (meta.getTypeName().equals(metaName)) { return meta; } } for (LuaObjectMeta meta : Lua.META.values()) { if (meta.getTypeName().equals(metaName)) { return meta; } } return null; }
/** * Returns the {@link LuaObjectMeta} associated with the provided object. * * <p>If the provided object is an instance of {@link LuaImplementable} and has a primary * identifying class, the meta associated with that class is scanned for first. * * @param obj the Object to query with * @return the LuaObjectMeta associated with the provided object, or null if one was not found */ public static LuaObjectMeta getMeta(Object obj) { if (obj == null) { return null; } Class<?> target = null; if (obj instanceof LuaImplementable && ((LuaImplementable<?>) obj).getPrimaryIdentifyingClass() != null) { target = ((LuaImplementable<?>) obj).getPrimaryIdentifyingClass(); } else { target = obj.getClass(); } do { if (Lua.PMETA.containsKey(target)) { return Lua.PMETA.get(target); } if (Lua.META.containsKey(target)) { return Lua.META.get(target); } for (LuaObjectMeta meta : Lua.PMETA.values()) { if (meta.getTargetObjectClass().isInstance(obj)) { return meta; } } for (LuaObjectMeta meta : Lua.META.values()) { if (meta.getTargetObjectClass().isInstance(obj)) { return meta; } } if (target != obj.getClass()) { target = obj.getClass(); } else { target = null; } } while (target != null); return null; }
/** * Injects all registered metatables into the provided table, with the owning meta's typename as * their keys. * * <p>Should only be used by {@link MetaLib}. */ public static void injectMetatables(LuaTable table) { Lua.PMETA .values() .forEach( meta -> { if (meta.getMetatable() != null) { table.set(meta.getTypeName(), meta.getMetatable()); } }); Lua.META .values() .forEach( meta -> { if (meta.getMetatable() != null) { table.set(meta.getTypeName(), meta.getMetatable()); } }); }