blob: 1c94fa81424e14552150d7e1523a4b7df80726ff [file] [log] [blame] [raw]
package li.cil.oc.server.computer
import java.lang.reflect.Method
import com.naef.jnlua.JavaFunction
import com.naef.jnlua.LuaState
import li.cil.oc.api.Callback
import li.cil.oc.api.IDriver
import li.cil.oc.common.computer.IInternalComputerContext
private[oc] class Driver(val driver: IDriver) {
def injectInto(context: IInternalComputerContext) {
// Check if the component actually provides an API.
val api = driver.apiName
if (api == null || api.isEmpty()) return
val lua = context.luaState
// Get or create table holding API tables.
lua.getGlobal("drivers") // ... drivers?
assert(!lua.isNil(-1)) // ... drivers
// Get or create API table.
lua.getField(-1, api) // ... drivers api?
if (lua.isNil(-1)) { // ... drivers nil
lua.pop(1) // ... drivers
lua.newTable() // ... drivers api
lua.pushValue(-1) // ... drivers api api
lua.setField(-3, api) // ... drivers api
} // ... drivers api
for (method <- driver.getClass().getMethods())
method.getAnnotation(classOf[Callback]) match {
case null => Unit // No annotation.
case annotation => {
val name = annotation.name
lua.getField(-1, name) // ... drivers api func?
if (lua.isNil(-1)) { // ... drivers api nil
// No such entry yet.
lua.pop(1) // ... drivers api
lua.pushJavaFunction(new MethodWrapper(context, method)) // ... drivers api func
lua.setField(-2, name) // ... drivers api
}
else { // ... drivers api func
// Entry already exists, skip it.
lua.pop(1) // ... drivers api
// TODO Log warning properly via a logger.
println("WARNING: Duplicate API entry, ignoring: " + api + "." + name)
}
}
} // ... drivers api
lua.pop(2) // ...
}
private class MethodWrapper(val context: IInternalComputerContext, val method: Method) extends JavaFunction {
def invoke(state: LuaState): Int = {
return 0
}
}
/*
private class MethodWrapper(val context: IInternalComputerContext, val method: Method) extends JavaFunction {
private val classOfBoolean = classOf[Boolean]
private val classOfByte = classOf[Byte]
private val classOfShort = classOf[Short]
private val classOfInteger = classOf[Int]
private val classOfLong = classOf[Long]
private val classOfFloat = classOf[Float]
private val classOfDouble = classOf[Double]
private val classOfString = classOf[String]
private val parameterTypes = method.getParameterTypes.zipWithIndex
private val parameterCount = parameterTypes.size
private val returnType = method.getReturnType
private val returnsTuple = returnType.isInstanceOf[Array[Object]]
private val returnsNothing = returnType.equals(Void.TYPE)
// TODO Rework all of this, most likely won't work because of type erasure.
def invoke(state: LuaState): Int = {
// Parse the parameters, convert them to Java types.
val parameters = Array(context) ++ parameterTypes.map {
//case (classOfBoolean, i) => boolean2Boolean(state.checkBoolean(i + 1))
case (classOfByte, i) => java.lang.Byte.valueOf(state.checkInteger(i + 1).toByte)
case (classOfShort, i) => java.lang.Short.valueOf(state.checkInteger(i + 1).toShort)
case (classOfInteger, i) => java.lang.Integer.valueOf(state.checkInteger(i + 1))
case (classOfLong, i) => java.lang.Long.valueOf(state.checkInteger(i + 1).toLong)
case (classOfFloat, i) => java.lang.Float.valueOf(state.checkNumber(i + 1).toFloat)
case (classOfDouble, i) => java.lang.Double.valueOf(state.checkNumber(i + 1))
case (classOfString, i) => state.checkString(i + 1)
case _ => null
}
// Call the actual function, grab the result, if any.
val result = call(parameters: _*)
// Check the result, convert it to Lua.
if (returnsTuple) {
val array = result.asInstanceOf[Array[Object]]
array.foreach(v => push(state, v, v.getClass()))
return array.length
}
else if (returnsNothing) {
return 0
}
else {
push(state, result, returnType)
return 1
}
}
private def push(state: LuaState, value: Object, clazz: Class[_]) = clazz match {
case classOfBoolean => state.pushBoolean(value.asInstanceOf[Boolean])
case classOfInteger => state.pushNumber(value.asInstanceOf[Int])
case classOfDouble => state.pushNumber(value.asInstanceOf[Double])
case classOfString => state.pushString(value.asInstanceOf[String])
case _ => state.pushNil()
}
protected def call(args: AnyRef*) = {
method.invoke(driver, args)
}
}
*/
}