Skip to content

Commit

Permalink
ffi: explicit parameter type conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
azenla committed Sep 12, 2023
1 parent 4053c58 commit 260c9f4
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
11 changes: 9 additions & 2 deletions ffi/src/main/kotlin/gay/pizza/pork/ffi/FfiFunctionDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package gay.pizza.pork.ffi
class FfiFunctionDefinition(
val library: String,
val function: String,
val returnType: String
val returnType: String,
val parameters: List<String>
) {
companion object {
fun parse(def: String): FfiFunctionDefinition {
Expand All @@ -15,7 +16,13 @@ class FfiFunctionDefinition(
"but '${def}' was specified")
}
val (library, function, returnType) = parts
return FfiFunctionDefinition(library, function, returnType)
val parametersString = if (parts.size == 4) parts[3] else ""
return FfiFunctionDefinition(
library,
function,
returnType,
parametersString.split(",")
)
}
}
}
51 changes: 49 additions & 2 deletions ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gay.pizza.pork.ffi

import com.sun.jna.Function
import com.sun.jna.Pointer
import gay.pizza.pork.ast.ArgumentSpec
import gay.pizza.pork.evaluator.CallableFunction
import gay.pizza.pork.evaluator.NativeProvider
Expand All @@ -12,20 +13,22 @@ class JnaNativeProvider : NativeProvider {
return CallableFunction { functionArgs ->
val ffiArgs = mutableListOf<Any?>()
for ((index, spec) in arguments.withIndex()) {
val ffiType = functionDefinition.parameters[index]
if (spec.multiple) {
val variableArguments = functionArgs.values
.subList(index, functionArgs.values.size)
ffiArgs.addAll(variableArguments)
break
} else {
ffiArgs.add(functionArgs.values[index])
val converted = convert(ffiType, functionArgs.values[index])
ffiArgs.add(converted)
}
}
invoke(function, ffiArgs.toTypedArray(), functionDefinition.returnType)
}
}

private fun invoke(function: Function, values: Array<Any?>, type: String): Any = when (type) {
private fun invoke(function: Function, values: Array<Any?>, type: String): Any = when (rewriteType(type)) {
"void*" -> function.invokePointer(values)
"int" -> function.invokeInt(values)
"long" -> function.invokeLong(values)
Expand All @@ -35,4 +38,48 @@ class JnaNativeProvider : NativeProvider {
"char*" -> function.invokeString(values, false)
else -> throw RuntimeException("Unsupported ffi return type: $type")
}

private fun rewriteType(type: String): String = when (type) {
"size_t" -> "long"
else -> type
}

private fun convert(type: String, value: Any?): Any? = when (rewriteType(type)) {
"short" -> numberConvert(type, value) { toShort() }
"unsigned short" -> numberConvert(type, value) { toShort().toUShort() }
"int" -> numberConvert(type, value) { toInt() }
"unsigned int" -> numberConvert(type, value) { toInt().toUInt() }
"long" -> numberConvert(type, value) { toLong() }
"unsigned long" -> numberConvert(type, value) { toLong().toULong() }
"double" -> numberConvert(type, value) { toDouble() }
"float" -> numberConvert(type, value) { toFloat() }
"char*" -> notNullConvert(type, value) { toString() }
"void*" -> nullableConvert(type, value) { this as Pointer }
else -> throw RuntimeException("Unsupported ffi type: $type")
}

private fun <T> notNullConvert(type: String, value: Any?, into: Any.() -> T): T {
if (value == null) {
throw RuntimeException("Null values cannot be used for converting to type $type")
}
return into(value)
}

private fun <T> nullableConvert(type: String, value: Any?, into: Any.() -> T): T? {
if (value == null) {
return null
}
return into(value)
}

private fun <T> numberConvert(type: String, value: Any?, into: Number.() -> T): T {
if (value == null) {
throw RuntimeException("Null values cannot be used for converting to numeric type $type")
}

if (value !is Number) {
throw RuntimeException("Cannot convert value '$value' into type $type")
}
return into(value)
}
}

0 comments on commit 260c9f4

Please sign in to comment.