Move everything under kotlin-native folder
I was forced to manually do update the following files, because otherwise they would be ignored according .gitignore settings. Probably they should be deleted from repo. Interop/.idea/compiler.xml Interop/.idea/gradle.xml Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_3.xml Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_3.xml Interop/.idea/modules.xml Interop/.idea/modules/Indexer/Indexer.iml Interop/.idea/modules/Runtime/Runtime.iml Interop/.idea/modules/StubGenerator/StubGenerator.iml backend.native/backend.native.iml backend.native/bc.frontend/bc.frontend.iml backend.native/cli.bc/cli.bc.iml backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt backend.native/tests/link/lib/foo.kt backend.native/tests/link/lib/foo2.kt backend.native/tests/teamcity-test.property
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'c'
|
||||
|
||||
buildscript {
|
||||
ext.rootBuildDirectory = file('../..')
|
||||
|
||||
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
classpath "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
|
||||
}
|
||||
}
|
||||
import org.jetbrains.kotlin.konan.target.ClangArgs
|
||||
|
||||
|
||||
model {
|
||||
components {
|
||||
callbacks(NativeLibrarySpec) {
|
||||
sources.c.source {
|
||||
srcDir 'src/callbacks/c'
|
||||
include '**/*.c'
|
||||
}
|
||||
binaries.all {
|
||||
def host = rootProject.ext.hostName
|
||||
|
||||
def hostLibffiDir = rootProject.ext.get("${host}LibffiDir")
|
||||
|
||||
cCompiler.args hostPlatform.clang.hostCompilerArgsForJni
|
||||
cCompiler.args "-I$hostLibffiDir/include"
|
||||
|
||||
linker.args "$hostLibffiDir/lib/libffi.a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toolChains {
|
||||
clang(Clang) {
|
||||
eachPlatform {
|
||||
cCompiler.withArguments(ClangArgs.&filterGradleNativeSoftwareFlags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url buildKotlinCompilerRepo
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":utilities:basic-utils")
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
}
|
||||
|
||||
sourceSets.main.kotlin.srcDirs += "src/jvm/kotlin"
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = ['-Xuse-experimental=kotlin.ExperimentalUnsignedTypes', '-Xuse-experimental=kotlin.Experimental',
|
||||
'-Xopt-in=kotlin.RequiresOptIn', "-XXLanguage:+InlineClasses"]
|
||||
allWarningsAsErrors=true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task nativelibs(type: Copy) {
|
||||
dependsOn 'callbacksSharedLibrary'
|
||||
|
||||
from "$buildDir/libs/callbacks/shared/"
|
||||
into "$buildDir/nativelibs/"
|
||||
}
|
||||
|
||||
classes.dependsOn nativelibs
|
||||
@@ -0,0 +1,243 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <jni.h>
|
||||
#include <ffi.h>
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeVoid
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeVoid(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_void;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeUInt8
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeUInt8(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_uint8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeSInt8
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeSInt8(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_sint8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeUInt16
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeUInt16(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_uint16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeSInt16
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeSInt16(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_sint16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeUInt32
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeUInt32(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_uint32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeSInt32
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeSInt32(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_sint32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeUInt64
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeUInt64(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_uint64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeSInt64
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeSInt64(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_sint64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypePointer
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypePointer(JNIEnv *env, jclass cls) {
|
||||
return (jlong) &ffi_type_pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiTypeStruct0
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiTypeStruct0(JNIEnv *env, jclass cls, jlong elements) {
|
||||
ffi_type* res = malloc(sizeof(ffi_type));
|
||||
if (res != NULL) {
|
||||
res->size = 0;
|
||||
res->alignment = 0;
|
||||
res->elements = (ffi_type**) elements;
|
||||
res->type = FFI_TYPE_STRUCT;
|
||||
}
|
||||
return (jlong) res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiCreateCif0
|
||||
* Signature: (IJJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiCreateCif0(JNIEnv *env, jclass cls, jint nArgs, jlong rType, jlong argTypes) {
|
||||
ffi_cif* res = malloc(sizeof(ffi_cif));
|
||||
if (res != NULL) {
|
||||
ffi_status status = ffi_prep_cif(res, FFI_DEFAULT_ABI, nArgs, (ffi_type*)rType, (ffi_type**)argTypes);
|
||||
if (status != FFI_OK) {
|
||||
if (status == FFI_BAD_TYPEDEF) {
|
||||
return -(jlong)1;
|
||||
} else if (status == FFI_BAD_ABI) {
|
||||
return -(jlong)2;
|
||||
} else {
|
||||
return -(jlong)3;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (jlong) res;
|
||||
}
|
||||
|
||||
static JavaVM *vm = NULL;
|
||||
|
||||
// Returns the JNI env which can be used by the caller.
|
||||
// If current thread is not attached to JVM, then it gets attached as daemon.
|
||||
static JNIEnv* getCurrentEnv() {
|
||||
JNIEnv* env;
|
||||
assert(vm != NULL);
|
||||
jint res = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_1);
|
||||
if (res != JNI_OK) {
|
||||
assert(res == JNI_EDETACHED);
|
||||
res = (*vm)->AttachCurrentThreadAsDaemon(vm, (void**)&env, NULL);
|
||||
assert(res == JNI_OK);
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm_, void *reserved) {
|
||||
vm = vm_;
|
||||
return JNI_VERSION_1_1;
|
||||
}
|
||||
|
||||
// Checks for pending exception. If there is one, describes it and terminates the process.
|
||||
static void checkException(JNIEnv *env) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void ffi_fun(ffi_cif *cif, void *ret, void **args, void *user_data) {
|
||||
JNIEnv* env = getCurrentEnv();
|
||||
|
||||
static jmethodID acceptFun = NULL;
|
||||
static jclass cls = NULL;
|
||||
if (acceptFun == NULL) {
|
||||
// Note: in some cases [FindClass] below may use a classloader different from the one loaded interop classes,
|
||||
// so stick to JVM-provided class:
|
||||
jclass clsLocal = (*env)->FindClass(env, "java/util/function/LongConsumer");
|
||||
checkException(env);
|
||||
assert(clsLocal != NULL);
|
||||
|
||||
cls = (jclass) (*env)->NewGlobalRef(env, clsLocal);
|
||||
checkException(env);
|
||||
assert(cls != NULL);
|
||||
|
||||
acceptFun = (*env)->GetMethodID(env, cls, "accept", "(J)V");
|
||||
checkException(env);
|
||||
assert(acceptFun != NULL);
|
||||
}
|
||||
|
||||
jlong retAndArgs[2] = { (jlong)ret, (jlong)args }; // Unpacked in [ffiClosureImpl].
|
||||
(*env)->CallVoidMethod(env, (jobject) user_data, acceptFun, (jlong)(intptr_t)&retAndArgs[0]);
|
||||
checkException(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: ffiCreateClosure0
|
||||
* Signature: (JLjava/lang/Object;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_ffiCreateClosure0(JNIEnv *env, jclass cls, jlong ffiCif, jobject userData) {
|
||||
jobject userDataGlobalRef = (*env)->NewGlobalRef(env, userData);
|
||||
if (userDataGlobalRef == NULL) {
|
||||
return (jlong)0;
|
||||
}
|
||||
|
||||
assert(sizeof(jobject) == sizeof(void*)); // TODO: check statically
|
||||
void* userDataPtr = (void*) userDataGlobalRef;
|
||||
|
||||
void* res;
|
||||
ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), &res);
|
||||
if (closure == NULL) {
|
||||
return (jlong)0;
|
||||
}
|
||||
ffi_status status = ffi_prep_closure_loc(closure, (ffi_cif*)ffiCif, ffi_fun, userDataPtr, res);
|
||||
if (status != FFI_OK) {
|
||||
return -(jlong)1;
|
||||
}
|
||||
|
||||
return (jlong) res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: newGlobalRef
|
||||
* Signature: (Ljava/lang/Object;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_newGlobalRef(JNIEnv *env, jclass cls, jobject obj) {
|
||||
jobject res = (*env)->NewGlobalRef(env, obj);
|
||||
return (jlong) res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: derefGlobalRef
|
||||
* Signature: (J)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_derefGlobalRef(JNIEnv *env, jclass cls, jlong ref) {
|
||||
return (jobject) ref;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: kotlinx_cinterop_JvmCallbacksKt
|
||||
* Method: deleteGlobalRef
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_kotlinx_cinterop_JvmCallbacksKt_deleteGlobalRef(JNIEnv *env, jclass cls, jlong ref) {
|
||||
(*env)->DeleteGlobalRef(env, (jobject) ref);
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.function.LongConsumer
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.companionObjectInstance
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.jvm.reflect
|
||||
|
||||
internal fun createStablePointer(any: Any): COpaquePointer = newGlobalRef(any).toCPointer()!!
|
||||
|
||||
internal fun disposeStablePointer(pointer: COpaquePointer) = deleteGlobalRef(pointer.toLong())
|
||||
|
||||
@PublishedApi
|
||||
internal fun derefStablePointer(pointer: COpaquePointer): Any = derefGlobalRef(pointer.toLong())
|
||||
|
||||
private fun getFieldCType(type: KType): CType<*> {
|
||||
val classifier = type.classifier
|
||||
if (classifier is KClass<*> && classifier.isSubclassOf(CStructVar::class)) {
|
||||
return getStructCType(classifier)
|
||||
}
|
||||
|
||||
return getArgOrRetValCType(type)
|
||||
}
|
||||
|
||||
private fun getVariableCType(type: KType): CType<*>? {
|
||||
val classifier = type.classifier
|
||||
return when (classifier) {
|
||||
!is KClass<*> -> null
|
||||
ByteVarOf::class -> SInt8
|
||||
ShortVarOf::class -> SInt16
|
||||
IntVarOf::class -> SInt32
|
||||
LongVarOf::class -> SInt64
|
||||
CPointerVarOf::class -> Pointer
|
||||
// TODO: floats, enums.
|
||||
else -> if (classifier.isSubclassOf(CStructVar::class)) {
|
||||
getStructCType(classifier)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val structTypeCache = ConcurrentHashMap<Class<*>, CType<*>>()
|
||||
|
||||
private fun getStructCType(structClass: KClass<*>): CType<*> = structTypeCache.computeIfAbsent(structClass.java) {
|
||||
// Note that struct classes are not supposed to be user-defined,
|
||||
// so they don't require to be checked strictly.
|
||||
|
||||
val annotations = structClass.annotations
|
||||
val cNaturalStruct = annotations.filterIsInstance<CNaturalStruct>().firstOrNull() ?:
|
||||
error("struct ${structClass.simpleName} has custom layout")
|
||||
|
||||
val propertiesByName = structClass.declaredMemberProperties.groupBy { it.name }
|
||||
|
||||
val fields = cNaturalStruct.fieldNames.map {
|
||||
propertiesByName[it]!!.single()
|
||||
}
|
||||
|
||||
val fieldCTypes = mutableListOf<CType<*>>()
|
||||
|
||||
for (field in fields) {
|
||||
val lengthAnnotation = field.annotations.filterIsInstance<CLength>().firstOrNull()
|
||||
if (lengthAnnotation == null) {
|
||||
val fieldType = getFieldCType(field.returnType)
|
||||
fieldCTypes.add(fieldType)
|
||||
} else {
|
||||
assert(field.returnType.classifier == CPointer::class)
|
||||
val length = lengthAnnotation.value
|
||||
if (length != 0) {
|
||||
val pointed = field.returnType.arguments.single().type!!
|
||||
val pointedCType = getVariableCType(pointed) ?: TODO("array element type '$pointed'")
|
||||
|
||||
// Represent array field as repeated element-typed fields:
|
||||
repeat(length) {
|
||||
fieldCTypes.add(pointedCType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val structType = structClass.companionObjectInstance as CVariable.Type
|
||||
|
||||
Struct(structType.size, structType.align, fieldCTypes)
|
||||
}
|
||||
|
||||
private fun getStructValueCType(type: KType): CType<*> {
|
||||
val structClass = type.arguments.singleOrNull()?.type?.classifier as? KClass<*> ?:
|
||||
error("'$type' type is incomplete")
|
||||
|
||||
return getStructCType(structClass)
|
||||
}
|
||||
|
||||
private fun getEnumCType(classifier: KClass<*>): CEnumType? {
|
||||
val rawValueType = classifier.declaredMemberProperties.single().returnType
|
||||
|
||||
val rawValueCType = when (rawValueType.classifier) {
|
||||
Byte::class -> SInt8
|
||||
Short::class -> SInt16
|
||||
Int::class -> SInt32
|
||||
Long::class -> SInt64
|
||||
else -> error("'${classifier.simpleName}' has unexpected value type '$rawValueType'")
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return CEnumType(rawValueCType as CType<Any>)
|
||||
}
|
||||
|
||||
private fun getArgOrRetValCType(type: KType): CType<*> {
|
||||
val classifier = type.classifier
|
||||
|
||||
val result = when (classifier) {
|
||||
!is KClass<*> -> null
|
||||
Unit::class -> Void
|
||||
Byte::class -> SInt8
|
||||
Short::class -> SInt16
|
||||
Int::class -> SInt32
|
||||
Long::class -> SInt64
|
||||
CPointer::class -> Pointer
|
||||
// TODO: floats
|
||||
CValue::class -> getStructValueCType(type)
|
||||
else -> if (classifier.isSubclassOf(@Suppress("DEPRECATION") CEnum::class)) {
|
||||
getEnumCType(classifier)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: error("$type is not supported in callback signature")
|
||||
|
||||
if (type.isMarkedNullable != (classifier == CPointer::class)) {
|
||||
if (type.isMarkedNullable) {
|
||||
error("$type must not be nullable when used in callback signature")
|
||||
} else {
|
||||
error("$type must be nullable when used in callback signature")
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createStaticCFunction(function: Function<*>): CPointer<CFunction<*>> {
|
||||
val errorMessage = "staticCFunction must take an unbound, non-capturing function"
|
||||
|
||||
if (!isStatic(function)) {
|
||||
throw IllegalArgumentException(errorMessage)
|
||||
}
|
||||
|
||||
val kFunction = function as? KFunction<*> ?: function.reflect() ?:
|
||||
throw IllegalArgumentException(errorMessage)
|
||||
|
||||
val returnType = getArgOrRetValCType(kFunction.returnType)
|
||||
val paramTypes = kFunction.parameters.map { getArgOrRetValCType(it.type) }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return interpretCPointer(createStaticCFunctionImpl(returnType as CType<Any?>, paramTypes, function))!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if given function is *static* as defined in [staticCFunction].
|
||||
*/
|
||||
private fun isStatic(function: Function<*>): Boolean {
|
||||
// TODO: revise
|
||||
try {
|
||||
with(function.javaClass.getDeclaredField("INSTANCE")) {
|
||||
if (!java.lang.reflect.Modifier.isStatic(modifiers) || !java.lang.reflect.Modifier.isFinal(modifiers)) {
|
||||
return false
|
||||
}
|
||||
|
||||
isAccessible = true // TODO: undo
|
||||
|
||||
return get(null) == function
|
||||
|
||||
// If the class has static final "INSTANCE" field, and only the value of this field is accepted,
|
||||
// then each class is handled at most once, so these checks prevent memory leaks.
|
||||
}
|
||||
} catch (e: NoSuchFieldException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private val createdStaticFunctions = ConcurrentHashMap<Class<*>, CPointer<CFunction<*>>>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun <F : Function<*>> staticCFunctionImpl(function: F) =
|
||||
createdStaticFunctions.computeIfAbsent(function.javaClass) {
|
||||
createStaticCFunction(function)
|
||||
} as CPointer<CFunction<F>>
|
||||
|
||||
private val invokeMethods = (0 .. 22).map { arity ->
|
||||
Class.forName("kotlin.jvm.functions.Function$arity").getMethod("invoke",
|
||||
*Array<Class<*>>(arity) { java.lang.Object::class.java })
|
||||
}
|
||||
|
||||
private fun createStaticCFunctionImpl(
|
||||
returnType: CType<Any?>,
|
||||
paramTypes: List<CType<*>>,
|
||||
function: Function<*>
|
||||
): NativePtr {
|
||||
val ffiCif = ffiCreateCif(returnType.ffiType, paramTypes.map { it.ffiType })
|
||||
|
||||
val arity = paramTypes.size
|
||||
val pt = paramTypes.toTypedArray()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val impl: FfiClosureImpl = when (arity) {
|
||||
0 -> {
|
||||
val f = function as () -> Any?
|
||||
ffiClosureImpl(returnType) { _ ->
|
||||
f()
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
val f = function as (Any?) -> Any?
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
f(pt.read(args, 0))
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
val f = function as (Any?, Any?) -> Any?
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
f(pt.read(args, 0), pt.read(args, 1))
|
||||
}
|
||||
}
|
||||
3 -> {
|
||||
val f = function as (Any?, Any?, Any?) -> Any?
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
f(pt.read(args, 0), pt.read(args, 1), pt.read(args, 2))
|
||||
}
|
||||
}
|
||||
4 -> {
|
||||
val f = function as (Any?, Any?, Any?, Any?) -> Any?
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
f(pt.read(args, 0), pt.read(args, 1), pt.read(args, 2), pt.read(args, 3))
|
||||
}
|
||||
}
|
||||
5 -> {
|
||||
val f = function as (Any?, Any?, Any?, Any?, Any?) -> Any?
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
f(pt.read(args, 0), pt.read(args, 1), pt.read(args, 2), pt.read(args, 3), pt.read(args, 4))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val invokeMethod = invokeMethods[arity]
|
||||
ffiClosureImpl(returnType) { args ->
|
||||
val arguments = Array(arity) { pt.read(args, it) }
|
||||
invokeMethod.invoke(function, *arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ffiCreateClosure(ffiCif, impl)
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun Array<CType<*>>.read(args: CArrayPointer<COpaquePointerVar>, index: Int) =
|
||||
this[index].read(args[index].rawValue)
|
||||
|
||||
private inline fun ffiClosureImpl(
|
||||
returnType: CType<Any?>,
|
||||
crossinline invoke: (args: CArrayPointer<COpaquePointerVar>) -> Any?
|
||||
): FfiClosureImpl {
|
||||
// Called through [ffi_fun] when a native function created with [ffiCreateClosure] is invoked.
|
||||
return LongConsumer { retAndArgsRaw ->
|
||||
val retAndArgs = retAndArgsRaw.toCPointer<CPointerVar<*>>()!!
|
||||
|
||||
// Pointer to memory to be filled with return value of the invoked native function:
|
||||
val ret = retAndArgs[0]!!
|
||||
|
||||
// Pointer to array of pointers to arguments passed to the invoked native function:
|
||||
val args = retAndArgs[1]!!.reinterpret<COpaquePointerVar>()
|
||||
|
||||
val result = invoke(args)
|
||||
|
||||
returnType.write(ret.rawValue, result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the bridge between Kotlin type `T` and the corresponding C type of a function's parameter or return value.
|
||||
* It is supposed to be constructed using the primitive types (such as [SInt32]), the [Struct] combinator
|
||||
* and the [CEnumType] wrapper.
|
||||
*
|
||||
* This description omits the details that are irrelevant for the ABI.
|
||||
*/
|
||||
private abstract class CType<T> internal constructor(val ffiType: ffi_type) {
|
||||
internal constructor(ffiTypePtr: Long) : this(interpretPointed<ffi_type>(ffiTypePtr))
|
||||
abstract fun read(location: NativePtr): T
|
||||
abstract fun write(location: NativePtr, value: T): Unit
|
||||
}
|
||||
|
||||
private object Void : CType<Any?>(ffiTypeVoid()) {
|
||||
override fun read(location: NativePtr) = throw UnsupportedOperationException()
|
||||
|
||||
override fun write(location: NativePtr, value: Any?) {
|
||||
// nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
private object SInt8 : CType<Byte>(ffiTypeSInt8()) {
|
||||
override fun read(location: NativePtr) = interpretPointed<ByteVar>(location).value
|
||||
override fun write(location: NativePtr, value: Byte) {
|
||||
interpretPointed<ByteVar>(location).value = value
|
||||
}
|
||||
}
|
||||
|
||||
private object SInt16 : CType<Short>(ffiTypeSInt16()) {
|
||||
override fun read(location: NativePtr) = interpretPointed<ShortVar>(location).value
|
||||
override fun write(location: NativePtr, value: Short) {
|
||||
interpretPointed<ShortVar>(location).value = value
|
||||
}
|
||||
}
|
||||
|
||||
private object SInt32 : CType<Int>(ffiTypeSInt32()) {
|
||||
override fun read(location: NativePtr) = interpretPointed<IntVar>(location).value
|
||||
override fun write(location: NativePtr, value: Int) {
|
||||
interpretPointed<IntVar>(location).value = value
|
||||
}
|
||||
}
|
||||
|
||||
private object SInt64 : CType<Long>(ffiTypeSInt64()) {
|
||||
override fun read(location: NativePtr) = interpretPointed<LongVar>(location).value
|
||||
override fun write(location: NativePtr, value: Long) {
|
||||
interpretPointed<LongVar>(location).value = value
|
||||
}
|
||||
}
|
||||
private object Pointer : CType<CPointer<*>?>(ffiTypePointer()) {
|
||||
override fun read(location: NativePtr) = interpretPointed<CPointerVar<*>>(location).value
|
||||
override fun write(location: NativePtr, value: CPointer<*>?) {
|
||||
interpretPointed<CPointerVar<*>>(location).value = value
|
||||
}
|
||||
}
|
||||
|
||||
private class Struct(val size: Long, val align: Int, elementTypes: List<CType<*>>) : CType<CValue<*>>(
|
||||
ffiTypeStruct(
|
||||
elementTypes.map { it.ffiType }
|
||||
)
|
||||
) {
|
||||
override fun read(location: NativePtr) = interpretPointed<ByteVar>(location).readValue<CStructVar>(size, align)
|
||||
|
||||
override fun write(location: NativePtr, value: CValue<*>) = value.write(location)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private class CEnumType(private val rawValueCType: CType<Any>) : CType<CEnum>(rawValueCType.ffiType) {
|
||||
|
||||
override fun read(location: NativePtr): CEnum {
|
||||
TODO("enum-typed callback parameters")
|
||||
}
|
||||
|
||||
override fun write(location: NativePtr, value: CEnum) {
|
||||
rawValueCType.write(location, value.value)
|
||||
}
|
||||
}
|
||||
|
||||
private typealias FfiClosureImpl = LongConsumer
|
||||
private typealias UserData = FfiClosureImpl
|
||||
|
||||
private val topLevelInitializer = loadKonanLibrary("callbacks")
|
||||
|
||||
|
||||
/**
|
||||
* Reference to `ffi_type` struct instance.
|
||||
*/
|
||||
internal class ffi_type(rawPtr: NativePtr) : COpaque(rawPtr)
|
||||
|
||||
/**
|
||||
* Reference to `ffi_cif` struct instance.
|
||||
*/
|
||||
internal class ffi_cif(rawPtr: NativePtr) : COpaque(rawPtr)
|
||||
|
||||
private external fun ffiTypeVoid(): Long
|
||||
private external fun ffiTypeUInt8(): Long
|
||||
private external fun ffiTypeSInt8(): Long
|
||||
private external fun ffiTypeUInt16(): Long
|
||||
private external fun ffiTypeSInt16(): Long
|
||||
private external fun ffiTypeUInt32(): Long
|
||||
private external fun ffiTypeSInt32(): Long
|
||||
private external fun ffiTypeUInt64(): Long
|
||||
private external fun ffiTypeSInt64(): Long
|
||||
private external fun ffiTypePointer(): Long
|
||||
|
||||
private external fun ffiTypeStruct0(elements: Long): Long
|
||||
|
||||
/**
|
||||
* Allocates and initializes `ffi_type` describing the struct.
|
||||
*
|
||||
* @param elements types of the struct elements
|
||||
*/
|
||||
private fun ffiTypeStruct(elementTypes: List<ffi_type>): ffi_type {
|
||||
val elements = nativeHeap.allocArrayOfPointersTo(*elementTypes.toTypedArray(), null)
|
||||
val res = ffiTypeStruct0(elements.rawValue)
|
||||
if (res == 0L) {
|
||||
throw OutOfMemoryError()
|
||||
}
|
||||
return interpretPointed(res)
|
||||
}
|
||||
|
||||
private external fun ffiCreateCif0(nArgs: Int, rType: Long, argTypes: Long): Long
|
||||
|
||||
/**
|
||||
* Creates and prepares an `ffi_cif`.
|
||||
*
|
||||
* @param returnType native function return value type
|
||||
* @param paramTypes native function parameter types
|
||||
*
|
||||
* @return the initialized `ffi_cif`
|
||||
*/
|
||||
private fun ffiCreateCif(returnType: ffi_type, paramTypes: List<ffi_type>): ffi_cif {
|
||||
val nArgs = paramTypes.size
|
||||
val argTypes = nativeHeap.allocArrayOfPointersTo(*paramTypes.toTypedArray(), null)
|
||||
val res = ffiCreateCif0(nArgs, returnType.rawPtr, argTypes.rawValue)
|
||||
|
||||
when (res) {
|
||||
0L -> throw OutOfMemoryError()
|
||||
-1L -> throw Error("FFI_BAD_TYPEDEF")
|
||||
-2L -> throw Error("FFI_BAD_ABI")
|
||||
-3L -> throw Error("libffi error occurred")
|
||||
}
|
||||
|
||||
return interpretPointed(res)
|
||||
}
|
||||
|
||||
private external fun ffiCreateClosure0(ffiCif: Long, userData: Any): Long
|
||||
|
||||
/**
|
||||
* Uses libffi to allocate a native function which will call [impl] when invoked.
|
||||
*
|
||||
* @param ffiCif describes the type of the function to create
|
||||
*/
|
||||
private fun ffiCreateClosure(ffiCif: ffi_cif, impl: FfiClosureImpl): NativePtr {
|
||||
val res = ffiCreateClosure0(ffiCif.rawPtr, userData = impl)
|
||||
|
||||
when (res) {
|
||||
0L -> throw OutOfMemoryError()
|
||||
-1L -> throw Error("libffi error occurred")
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
private external fun newGlobalRef(any: Any): Long
|
||||
private external fun derefGlobalRef(ref: Long): Any
|
||||
private external fun deleteGlobalRef(ref: Long)
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import sun.misc.Unsafe
|
||||
|
||||
private val NativePointed.address: Long
|
||||
get() = this.rawPtr
|
||||
|
||||
private enum class DataModel(val pointerSize: Long) {
|
||||
_32BIT(4),
|
||||
_64BIT(8)
|
||||
}
|
||||
|
||||
private val dataModel: DataModel = when (System.getProperty("sun.arch.data.model")) {
|
||||
null -> TODO()
|
||||
"32" -> DataModel._32BIT
|
||||
"64" -> DataModel._64BIT
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
// Must be only used in interop, contains host pointer size, not target!
|
||||
@PublishedApi
|
||||
internal val pointerSize: Int = dataModel.pointerSize.toInt()
|
||||
|
||||
@PublishedApi
|
||||
internal object nativeMemUtils {
|
||||
fun getByte(mem: NativePointed) = unsafe.getByte(mem.address)
|
||||
fun putByte(mem: NativePointed, value: Byte) = unsafe.putByte(mem.address, value)
|
||||
|
||||
fun getShort(mem: NativePointed) = unsafe.getShort(mem.address)
|
||||
fun putShort(mem: NativePointed, value: Short) = unsafe.putShort(mem.address, value)
|
||||
|
||||
fun getInt(mem: NativePointed) = unsafe.getInt(mem.address)
|
||||
fun putInt(mem: NativePointed, value: Int) = unsafe.putInt(mem.address, value)
|
||||
|
||||
fun getLong(mem: NativePointed) = unsafe.getLong(mem.address)
|
||||
fun putLong(mem: NativePointed, value: Long) = unsafe.putLong(mem.address, value)
|
||||
|
||||
fun getFloat(mem: NativePointed) = unsafe.getFloat(mem.address)
|
||||
fun putFloat(mem: NativePointed, value: Float) = unsafe.putFloat(mem.address, value)
|
||||
|
||||
fun getDouble(mem: NativePointed) = unsafe.getDouble(mem.address)
|
||||
fun putDouble(mem: NativePointed, value: Double) = unsafe.putDouble(mem.address, value)
|
||||
|
||||
fun getNativePtr(mem: NativePointed): NativePtr = when (dataModel) {
|
||||
DataModel._32BIT -> getInt(mem).toLong()
|
||||
DataModel._64BIT -> getLong(mem)
|
||||
}
|
||||
|
||||
fun putNativePtr(mem: NativePointed, value: NativePtr) = when (dataModel) {
|
||||
DataModel._32BIT -> putInt(mem, value.toInt())
|
||||
DataModel._64BIT -> putLong(mem, value)
|
||||
}
|
||||
|
||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||
unsafe.copyMemory(null, source.address, dest, byteArrayBaseOffset, length.toLong())
|
||||
}
|
||||
|
||||
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
|
||||
unsafe.copyMemory(source, byteArrayBaseOffset, null, dest.address, length.toLong())
|
||||
}
|
||||
|
||||
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
|
||||
unsafe.copyMemory(null, source.address, dest, charArrayBaseOffset, length.toLong() * 2)
|
||||
}
|
||||
|
||||
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
|
||||
unsafe.copyMemory(source, charArrayBaseOffset, null, dest.address, length.toLong() * 2)
|
||||
}
|
||||
|
||||
fun zeroMemory(dest: NativePointed, length: Int): Unit =
|
||||
unsafe.setMemory(dest.address, length.toLong(), 0)
|
||||
|
||||
fun copyMemory(dest: NativePointed, length: Int, src: NativePointed) =
|
||||
unsafe.copyMemory(src.address, dest.address, length.toLong())
|
||||
|
||||
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
inline fun <reified T> allocateInstance(): T {
|
||||
return unsafe.allocateInstance(T::class.java) as T
|
||||
}
|
||||
|
||||
fun alloc(size: Long, align: Int): NativePointed {
|
||||
val address = unsafe.allocateMemory(
|
||||
if (size == 0L) 1L else size // It is a hack: `sun.misc.Unsafe` can't allocate zero bytes
|
||||
)
|
||||
|
||||
if (address % align != 0L) TODO(align.toString())
|
||||
return interpretOpaquePointed(address)
|
||||
}
|
||||
|
||||
fun free(mem: NativePtr) {
|
||||
unsafe.freeMemory(mem)
|
||||
}
|
||||
|
||||
private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) {
|
||||
isAccessible = true
|
||||
return@with this.get(null) as Unsafe
|
||||
}
|
||||
|
||||
private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong()
|
||||
private val charArrayBaseOffset = unsafe.arrayBaseOffset(CharArray::class.java).toLong()
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.full.companionObjectInstance
|
||||
|
||||
typealias NativePtr = Long
|
||||
internal typealias NonNullNativePtr = NativePtr
|
||||
@PublishedApi internal fun NonNullNativePtr.toNativePtr() = this
|
||||
internal fun NativePtr.toNonNull(): NonNullNativePtr = this
|
||||
|
||||
public val nativeNullPtr: NativePtr = 0L
|
||||
|
||||
// TODO: the functions below should eventually be intrinsified
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private val typeOfCache = ConcurrentHashMap<Class<*>, CVariable.Type>()
|
||||
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
inline fun <reified T : CVariable> typeOf() =
|
||||
@Suppress("DEPRECATION")
|
||||
typeOfCache.computeIfAbsent(T::class.java) { T::class.companionObjectInstance as CVariable.Type }
|
||||
|
||||
/**
|
||||
* Returns interpretation of entity with given pointer, or `null` if it is null.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
inline fun <reified T : NativePointed> interpretNullablePointed(ptr: NativePtr): T? {
|
||||
if (ptr == nativeNullPtr) {
|
||||
return null
|
||||
} else {
|
||||
val result = nativeMemUtils.allocateInstance<T>()
|
||||
result.rawPtr = ptr
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [CPointer] from the raw pointer of [NativePtr].
|
||||
*
|
||||
* @return a [CPointer] representation, or `null` if the [rawValue] represents native `nullptr`.
|
||||
*/
|
||||
fun <T : CPointed> interpretCPointer(rawValue: NativePtr) =
|
||||
if (rawValue == nativeNullPtr) {
|
||||
null
|
||||
} else {
|
||||
CPointer<T>(rawValue)
|
||||
}
|
||||
|
||||
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=0x%x)".format(rawValue)
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class CLength(val value: Int)
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class CNaturalStruct(vararg val fieldNames: String)
|
||||
|
||||
fun <R> staticCFunction(function: () -> R): CPointer<CFunction<() -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, R> staticCFunction(function: (P1) -> R): CPointer<CFunction<(P1) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, R> staticCFunction(function: (P1, P2) -> R): CPointer<CFunction<(P1, P2) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, R> staticCFunction(function: (P1, P2, P3) -> R): CPointer<CFunction<(P1, P2, P3) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, R> staticCFunction(function: (P1, P2, P3, P4) -> R): CPointer<CFunction<(P1, P2, P3, P4) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, R> staticCFunction(function: (P1, P2, P3, P4, P5) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
|
||||
fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>> =
|
||||
staticCFunctionImpl(function)
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import org.jetbrains.kotlin.konan.util.KonanHomeProvider
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
|
||||
internal fun decodeFromUtf8(bytes: ByteArray) = String(bytes)
|
||||
internal fun encodeToUtf8(str: String) = str.toByteArray()
|
||||
|
||||
fun bitsToFloat(bits: Int): Float = java.lang.Float.intBitsToFloat(bits)
|
||||
fun bitsToDouble(bits: Long): Double = java.lang.Double.longBitsToDouble(bits)
|
||||
|
||||
// TODO: the functions below should eventually be intrinsified
|
||||
|
||||
inline fun <reified R : Number> Byte.signExtend(): R = when (R::class.java) {
|
||||
java.lang.Byte::class.java -> this.toByte() as R
|
||||
java.lang.Short::class.java -> this.toShort() as R
|
||||
java.lang.Integer::class.java -> this.toInt() as R
|
||||
java.lang.Long::class.java -> this.toLong() as R
|
||||
else -> this.invalidSignExtension()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Short.signExtend(): R = when (R::class.java) {
|
||||
java.lang.Short::class.java -> this.toShort() as R
|
||||
java.lang.Integer::class.java -> this.toInt() as R
|
||||
java.lang.Long::class.java -> this.toLong() as R
|
||||
else -> this.invalidSignExtension()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Int.signExtend(): R = when (R::class.java) {
|
||||
java.lang.Integer::class.java -> this.toInt() as R
|
||||
java.lang.Long::class.java -> this.toLong() as R
|
||||
else -> this.invalidSignExtension()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Long.signExtend(): R = when (R::class.java) {
|
||||
java.lang.Long::class.java -> this.toLong() as R
|
||||
else -> this.invalidSignExtension()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Number.invalidSignExtension(): R {
|
||||
throw Error("unable to sign extend ${this.javaClass.simpleName} \"${this}\" to ${R::class.java.simpleName}")
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Byte.narrow(): R = when (R::class.java) {
|
||||
java.lang.Byte::class.java -> this.toByte() as R
|
||||
else -> this.invalidNarrowing()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Short.narrow(): R = when (R::class.java) {
|
||||
java.lang.Byte::class.java -> this.toByte() as R
|
||||
java.lang.Short::class.java -> this.toShort() as R
|
||||
else -> this.invalidNarrowing()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Int.narrow(): R = when (R::class.java) {
|
||||
java.lang.Byte::class.java -> this.toByte() as R
|
||||
java.lang.Short::class.java -> this.toShort() as R
|
||||
java.lang.Integer::class.java -> this.toInt() as R
|
||||
else -> this.invalidNarrowing()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Long.narrow(): R = when (R::class.java) {
|
||||
java.lang.Byte::class.java -> this.toByte() as R
|
||||
java.lang.Short::class.java -> this.toShort() as R
|
||||
java.lang.Integer::class.java -> this.toInt() as R
|
||||
java.lang.Long::class.java -> this.toLong() as R
|
||||
else -> this.invalidNarrowing()
|
||||
}
|
||||
|
||||
inline fun <reified R : Number> Number.invalidNarrowing(): R {
|
||||
throw Error("unable to narrow ${this.javaClass.simpleName} \"${this}\" to ${R::class.java.simpleName}")
|
||||
}
|
||||
|
||||
fun loadKonanLibrary(name: String) {
|
||||
try {
|
||||
System.loadLibrary(name)
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
val fullLibraryName = System.mapLibraryName(name)
|
||||
val dir = "${KonanHomeProvider.determineKonanHome()}/konan/nativelib"
|
||||
try {
|
||||
System.load("$dir/$fullLibraryName")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
val tempDir = createTempDir(directory = File(dir)).absolutePath
|
||||
Files.createLink(Paths.get(tempDir, fullLibraryName), Paths.get(dir, fullLibraryName))
|
||||
// TODO: Does not work on Windows. May be use FILE_FLAG_DELETE_ON_CLOSE?
|
||||
File(tempDir).deleteOnExit()
|
||||
File("$tempDir/$fullLibraryName").deleteOnExit()
|
||||
System.load("$tempDir/$fullLibraryName")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("FINAL_UPPER_BOUND", "NOTHING_TO_INLINE")
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
@JvmName("plus\$Byte")
|
||||
inline operator fun <T : ByteVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 1)
|
||||
|
||||
@JvmName("plus\$Byte")
|
||||
inline operator fun <T : ByteVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Byte")
|
||||
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Byte")
|
||||
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Byte")
|
||||
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Byte")
|
||||
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$Short")
|
||||
inline operator fun <T : ShortVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 2)
|
||||
|
||||
@JvmName("plus\$Short")
|
||||
inline operator fun <T : ShortVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Short")
|
||||
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Short")
|
||||
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Short")
|
||||
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Short")
|
||||
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$Int")
|
||||
inline operator fun <T : IntVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 4)
|
||||
|
||||
@JvmName("plus\$Int")
|
||||
inline operator fun <T : IntVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Int")
|
||||
inline operator fun <T : Int> CPointer<IntVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Int")
|
||||
inline operator fun <T : Int> CPointer<IntVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Int")
|
||||
inline operator fun <T : Int> CPointer<IntVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Int")
|
||||
inline operator fun <T : Int> CPointer<IntVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$Long")
|
||||
inline operator fun <T : LongVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 8)
|
||||
|
||||
@JvmName("plus\$Long")
|
||||
inline operator fun <T : LongVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Long")
|
||||
inline operator fun <T : Long> CPointer<LongVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Long")
|
||||
inline operator fun <T : Long> CPointer<LongVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Long")
|
||||
inline operator fun <T : Long> CPointer<LongVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Long")
|
||||
inline operator fun <T : Long> CPointer<LongVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$UByte")
|
||||
inline operator fun <T : UByteVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 1)
|
||||
|
||||
@JvmName("plus\$UByte")
|
||||
inline operator fun <T : UByteVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$UByte")
|
||||
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$UShort")
|
||||
inline operator fun <T : UShortVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 2)
|
||||
|
||||
@JvmName("plus\$UShort")
|
||||
inline operator fun <T : UShortVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$UShort")
|
||||
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$UShort")
|
||||
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$UInt")
|
||||
inline operator fun <T : UIntVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 4)
|
||||
|
||||
@JvmName("plus\$UInt")
|
||||
inline operator fun <T : UIntVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$UInt")
|
||||
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$UInt")
|
||||
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$ULong")
|
||||
inline operator fun <T : ULongVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 8)
|
||||
|
||||
@JvmName("plus\$ULong")
|
||||
inline operator fun <T : ULongVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$ULong")
|
||||
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$ULong")
|
||||
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$Float")
|
||||
inline operator fun <T : FloatVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 4)
|
||||
|
||||
@JvmName("plus\$Float")
|
||||
inline operator fun <T : FloatVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Float")
|
||||
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Float")
|
||||
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Float")
|
||||
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Float")
|
||||
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("plus\$Double")
|
||||
inline operator fun <T : DoubleVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * 8)
|
||||
|
||||
@JvmName("plus\$Double")
|
||||
inline operator fun <T : DoubleVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@JvmName("get\$Double")
|
||||
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.get(index: Int): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Double")
|
||||
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.set(index: Int, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@JvmName("get\$Double")
|
||||
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.get(index: Long): T =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@JvmName("set\$Double")
|
||||
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.set(index: Long, value: T) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
/* Generated by:
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
function gen {
|
||||
echo "@JvmName(\"plus\\\$$1\")"
|
||||
echo "inline operator fun <T : ${1}VarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? ="
|
||||
echo " interpretCPointer(this.rawValue + index * ${2})"
|
||||
echo
|
||||
echo "@JvmName(\"plus\\\$$1\")"
|
||||
echo "inline operator fun <T : ${1}VarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? ="
|
||||
echo " this + index.toLong()"
|
||||
echo
|
||||
echo "@JvmName(\"get\\\$$1\")"
|
||||
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.get(index: Int): T ="
|
||||
echo " (this + index)!!.pointed.value"
|
||||
echo
|
||||
echo "@JvmName(\"set\\\$$1\")"
|
||||
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.set(index: Int, value: T) {"
|
||||
echo " (this + index)!!.pointed.value = value"
|
||||
echo '}'
|
||||
echo
|
||||
echo "@JvmName(\"get\\\$$1\")"
|
||||
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.get(index: Long): T ="
|
||||
echo " (this + index)!!.pointed.value"
|
||||
echo
|
||||
echo "@JvmName(\"set\\\$$1\")"
|
||||
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.set(index: Long, value: T) {"
|
||||
echo " (this + index)!!.pointed.value = value"
|
||||
echo '}'
|
||||
echo
|
||||
}
|
||||
|
||||
gen Byte 1
|
||||
gen Short 2
|
||||
gen Int 4
|
||||
gen Long 8
|
||||
gen UByte 1
|
||||
gen UShort 2
|
||||
gen UInt 4
|
||||
gen ULong 8
|
||||
gen Float 4
|
||||
gen Double 8
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
@Deprecated("Use StableRef<T> instead", ReplaceWith("StableRef<T>"), DeprecationLevel.ERROR)
|
||||
typealias StableObjPtr = StableRef<*>
|
||||
|
||||
/**
|
||||
* This class provides a way to create a stable handle to any Kotlin object.
|
||||
* After [converting to CPointer][asCPointer] it can be safely passed to native code e.g. to be received
|
||||
* in a Kotlin callback.
|
||||
*
|
||||
* Any [StableRef] should be manually [disposed][dispose]
|
||||
*/
|
||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
||||
public inline class StableRef<out T : Any> @PublishedApi internal constructor(
|
||||
private val stablePtr: COpaquePointer
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Creates a handle for given object.
|
||||
*/
|
||||
fun <T : Any> create(any: T) = StableRef<T>(createStablePointer(any))
|
||||
|
||||
/**
|
||||
* Creates [StableRef] from given raw value.
|
||||
*
|
||||
* @param value must be a [value] of some [StableRef]
|
||||
*/
|
||||
@Deprecated("Use CPointer<*>.asStableRef<T>() instead", ReplaceWith("ptr.asStableRef<T>()"),
|
||||
DeprecationLevel.ERROR)
|
||||
fun fromValue(value: COpaquePointer) = value.asStableRef<Any>()
|
||||
}
|
||||
@Deprecated("Use .asCPointer() instead", ReplaceWith("this.asCPointer()"), DeprecationLevel.ERROR)
|
||||
val value: COpaquePointer get() = this.asCPointer()
|
||||
|
||||
/**
|
||||
* Converts the handle to C pointer.
|
||||
* @see [asStableRef]
|
||||
*/
|
||||
fun asCPointer(): COpaquePointer = this.stablePtr
|
||||
|
||||
/**
|
||||
* Disposes the handle. It must not be used after that.
|
||||
*/
|
||||
fun dispose() {
|
||||
disposeStablePointer(this.stablePtr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object this handle was [created][StableRef.create] for.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun get() = derefStablePointer(this.stablePtr) as T
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to [StableRef] this opaque pointer produced by [StableRef.asCPointer].
|
||||
*/
|
||||
inline fun <reified T : Any> CPointer<*>.asStableRef(): StableRef<T> = StableRef<T>(this).also { it.get() }
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
/**
|
||||
* The entity which has an associated native pointer.
|
||||
* Subtypes are supposed to represent interpretations of the pointed data or code.
|
||||
*
|
||||
* This interface is likely to be handled by compiler magic and shouldn't be subtyped by arbitrary classes.
|
||||
*
|
||||
* TODO: the behavior of [equals], [hashCode] and [toString] differs on Native and JVM backends.
|
||||
*/
|
||||
public open class NativePointed internal constructor(rawPtr: NonNullNativePtr) {
|
||||
var rawPtr = rawPtr.toNativePtr()
|
||||
internal set
|
||||
}
|
||||
|
||||
// `null` value of `NativePointed?` is mapped to `nativeNullPtr`.
|
||||
public val NativePointed?.rawPtr: NativePtr
|
||||
get() = if (this != null) this.rawPtr else nativeNullPtr
|
||||
|
||||
/**
|
||||
* Returns interpretation of entity with given pointer.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : NativePointed> interpretPointed(ptr: NativePtr): T = interpretNullablePointed<T>(ptr)!!
|
||||
|
||||
private class OpaqueNativePointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
|
||||
|
||||
public fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed<OpaqueNativePointed>(ptr)
|
||||
public fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed<OpaqueNativePointed>(ptr)
|
||||
|
||||
/**
|
||||
* Changes the interpretation of the pointed data or code.
|
||||
*/
|
||||
public inline fun <reified T : NativePointed> NativePointed.reinterpret(): T = interpretPointed(this.rawPtr)
|
||||
|
||||
/**
|
||||
* C data or code.
|
||||
*/
|
||||
public abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull())
|
||||
|
||||
/**
|
||||
* Represents a reference to (possibly empty) sequence of C values.
|
||||
* It can be either a stable pointer [CPointer] or a sequence of immutable values [CValues].
|
||||
*
|
||||
* [CValuesRef] is designed to be used as Kotlin representation of pointer-typed parameters of C functions.
|
||||
* When passing [CPointer] as [CValuesRef] to the Kotlin binding method, the C function receives exactly this pointer.
|
||||
* Passing [CValues] has nearly the same semantics as passing by value: the C function receives
|
||||
* the pointer to the temporary copy of these values, and the caller can't observe the modifications to this copy.
|
||||
* The copy is valid until the C function returns.
|
||||
* There are also other implementations of [CValuesRef] that provide temporary pointer,
|
||||
* e.g. Kotlin Native specific [refTo] functions to pass primitive arrays directly to native.
|
||||
*/
|
||||
public abstract class CValuesRef<T : CPointed> {
|
||||
/**
|
||||
* If this reference is [CPointer], returns this pointer, otherwise
|
||||
* allocate storage value in the scope and return it.
|
||||
*/
|
||||
public abstract fun getPointer(scope: AutofreeScope): CPointer<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* The (possibly empty) sequence of immutable C values.
|
||||
* It is self-contained and doesn't depend on native memory.
|
||||
*/
|
||||
public abstract class CValues<T : CVariable> : CValuesRef<T>() {
|
||||
/**
|
||||
* Copies the values to [placement] and returns the pointer to the copy.
|
||||
*/
|
||||
public override fun getPointer(scope: AutofreeScope): CPointer<T> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
public override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is CValues<*>) return false
|
||||
|
||||
val thisBytes = this.getBytes()
|
||||
val otherBytes = other.getBytes()
|
||||
|
||||
if (thisBytes.size != otherBytes.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (index in 0 .. thisBytes.size - 1) {
|
||||
if (thisBytes[index] != otherBytes[index]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
var result = 0
|
||||
for (byte in this.getBytes()) {
|
||||
result = result * 31 + byte
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public abstract val size: Int
|
||||
|
||||
public abstract val align: Int
|
||||
|
||||
/**
|
||||
* Copy the referenced values to [placement] and return placement pointer.
|
||||
*/
|
||||
public abstract fun place(placement: CPointer<T>): CPointer<T>
|
||||
}
|
||||
|
||||
public fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(scope)
|
||||
|
||||
/**
|
||||
* The single immutable C value.
|
||||
* It is self-contained and doesn't depend on native memory.
|
||||
*
|
||||
* TODO: consider providing an adapter instead of subtyping [CValues].
|
||||
*/
|
||||
public abstract class CValue<T : CVariable> : CValues<T>()
|
||||
|
||||
/**
|
||||
* C pointer.
|
||||
*/
|
||||
public class CPointer<T : CPointed> internal constructor(@PublishedApi internal val value: NonNullNativePtr) : CValuesRef<T>() {
|
||||
|
||||
// TODO: replace by [value].
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline val rawValue: NativePtr get() = value.toNativePtr()
|
||||
|
||||
public override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true // fast path
|
||||
}
|
||||
|
||||
return (other is CPointer<*>) && (rawValue == other.rawValue)
|
||||
}
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
return rawValue.hashCode()
|
||||
}
|
||||
|
||||
public override fun toString() = this.cPointerToString()
|
||||
|
||||
public override fun getPointer(scope: AutofreeScope) = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pointer to this data or code.
|
||||
*/
|
||||
public val <T : CPointed> T.ptr: CPointer<T>
|
||||
get() = interpretCPointer(this.rawPtr)!!
|
||||
|
||||
/**
|
||||
* Returns the corresponding [CPointed].
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline val <reified T : CPointed> CPointer<T>.pointed: T
|
||||
get() = interpretPointed<T>(this.rawValue)
|
||||
|
||||
// `null` value of `CPointer?` is mapped to `nativeNullPtr`
|
||||
public val CPointer<*>?.rawValue: NativePtr
|
||||
get() = if (this != null) this.rawValue else nativeNullPtr
|
||||
|
||||
public fun <T : CPointed> CPointer<*>.reinterpret(): CPointer<T> = interpretCPointer(this.rawValue)!!
|
||||
|
||||
public fun <T : CPointed> CPointer<T>?.toLong() = this.rawValue.toLong()
|
||||
|
||||
public fun <T : CPointed> Long.toCPointer(): CPointer<T>? = interpretCPointer(nativeNullPtr + this)
|
||||
|
||||
/**
|
||||
* The [CPointed] without any specified interpretation.
|
||||
*/
|
||||
public abstract class COpaque(rawPtr: NativePtr) : CPointed(rawPtr) // TODO: should it correspond to COpaquePointer?
|
||||
|
||||
/**
|
||||
* The pointer with an opaque type.
|
||||
*/
|
||||
public typealias COpaquePointer = CPointer<out CPointed> // FIXME
|
||||
|
||||
/**
|
||||
* The variable containing a [COpaquePointer].
|
||||
*/
|
||||
public typealias COpaquePointerVar = CPointerVarOf<COpaquePointer>
|
||||
|
||||
/**
|
||||
* The C data variable located in memory.
|
||||
*
|
||||
* The non-abstract subclasses should represent the (complete) C data type and thus specify size and alignment.
|
||||
* Each such subclass must have a companion object which is a [Type].
|
||||
*/
|
||||
public abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) {
|
||||
|
||||
/**
|
||||
* The (complete) C data type.
|
||||
*
|
||||
* @param size the size in bytes of data of this type
|
||||
* @param align the alignments in bytes that is enough for this data type.
|
||||
* It may be greater than actually required for simplicity.
|
||||
*/
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
public open class Type(val size: Long, val align: Int) {
|
||||
|
||||
init {
|
||||
require(size % align == 0L)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
public inline fun <reified T : CVariable> sizeOf() = typeOf<T>().size
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
public inline fun <reified T : CVariable> alignOf() = typeOf<T>().align
|
||||
|
||||
/**
|
||||
* Returns the member of this [CStructVar] which is located by given offset in bytes.
|
||||
*/
|
||||
public inline fun <reified T : CPointed> CStructVar.memberAt(offset: Long): T {
|
||||
return interpretPointed<T>(this.rawPtr + offset)
|
||||
}
|
||||
|
||||
public inline fun <reified T : CVariable> CStructVar.arrayMemberAt(offset: Long): CArrayPointer<T> {
|
||||
return interpretCPointer<T>(this.rawPtr + offset)!!
|
||||
}
|
||||
|
||||
/**
|
||||
* The C struct-typed variable located in memory.
|
||||
*/
|
||||
public abstract class CStructVar(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
open class Type(size: Long, align: Int) : CVariable.Type(size, align)
|
||||
}
|
||||
|
||||
/**
|
||||
* The C primitive-typed variable located in memory.
|
||||
*/
|
||||
sealed class CPrimitiveVar(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
// aligning by size is obviously enough
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
open class Type(size: Int) : CVariable.Type(size.toLong(), align = size)
|
||||
}
|
||||
|
||||
@Deprecated("Will be removed.")
|
||||
public interface CEnum {
|
||||
public val value: Any
|
||||
}
|
||||
|
||||
public abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr)
|
||||
|
||||
// generics below are used for typedef support
|
||||
// these classes are not supposed to be used directly, instead the typealiases are provided.
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class BooleanVarOf<T : Boolean>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(1)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class ByteVarOf<T : Byte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(1)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class ShortVarOf<T : Short>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(2)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class IntVarOf<T : Int>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(4)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class LongVarOf<T : Long>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(8)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class UByteVarOf<T : UByte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(1)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class UShortVarOf<T : UShort>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(2)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class UIntVarOf<T : UInt>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(4)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class ULongVarOf<T : ULong>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(8)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class FloatVarOf<T : Float>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(4)
|
||||
}
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND")
|
||||
public class DoubleVarOf<T : Double>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(8)
|
||||
}
|
||||
|
||||
public typealias BooleanVar = BooleanVarOf<Boolean>
|
||||
public typealias ByteVar = ByteVarOf<Byte>
|
||||
public typealias ShortVar = ShortVarOf<Short>
|
||||
public typealias IntVar = IntVarOf<Int>
|
||||
public typealias LongVar = LongVarOf<Long>
|
||||
public typealias UByteVar = UByteVarOf<UByte>
|
||||
public typealias UShortVar = UShortVarOf<UShort>
|
||||
public typealias UIntVar = UIntVarOf<UInt>
|
||||
public typealias ULongVar = ULongVarOf<ULong>
|
||||
public typealias FloatVar = FloatVarOf<Float>
|
||||
public typealias DoubleVar = DoubleVarOf<Double>
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Boolean> BooleanVarOf<T>.value: T
|
||||
get() {
|
||||
val byte = nativeMemUtils.getByte(this)
|
||||
return byte.toBoolean() as T
|
||||
}
|
||||
set(value) = nativeMemUtils.putByte(this, value.toByte())
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun Boolean.toByte(): Byte = if (this) 1 else 0
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun Byte.toBoolean() = (this.toInt() != 0)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Byte> ByteVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getByte(this) as T
|
||||
set(value) = nativeMemUtils.putByte(this, value)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Short> ShortVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getShort(this) as T
|
||||
set(value) = nativeMemUtils.putShort(this, value)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Int> IntVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getInt(this) as T
|
||||
set(value) = nativeMemUtils.putInt(this, value)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Long> LongVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getLong(this) as T
|
||||
set(value) = nativeMemUtils.putLong(this, value)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : UByte> UByteVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getByte(this).toUByte() as T
|
||||
set(value) = nativeMemUtils.putByte(this, value.toByte())
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : UShort> UShortVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getShort(this).toUShort() as T
|
||||
set(value) = nativeMemUtils.putShort(this, value.toShort())
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : UInt> UIntVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getInt(this).toUInt() as T
|
||||
set(value) = nativeMemUtils.putInt(this, value.toInt())
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : ULong> ULongVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getLong(this).toULong() as T
|
||||
set(value) = nativeMemUtils.putLong(this, value.toLong())
|
||||
|
||||
// TODO: ensure native floats have the appropriate binary representation
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Float> FloatVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getFloat(this) as T
|
||||
set(value) = nativeMemUtils.putFloat(this, value)
|
||||
|
||||
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
|
||||
public var <T : Double> DoubleVarOf<T>.value: T
|
||||
get() = nativeMemUtils.getDouble(this) as T
|
||||
set(value) = nativeMemUtils.putDouble(this, value)
|
||||
|
||||
|
||||
public class CPointerVarOf<T : CPointer<*>>(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : CVariable.Type(pointerSize.toLong(), pointerSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* The C data variable containing the pointer to `T`.
|
||||
*/
|
||||
public typealias CPointerVar<T> = CPointerVarOf<CPointer<T>>
|
||||
|
||||
/**
|
||||
* The value of this variable.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline var <P : CPointer<*>> CPointerVarOf<P>.value: P?
|
||||
get() = interpretCPointer<CPointed>(nativeMemUtils.getNativePtr(this)) as P?
|
||||
set(value) = nativeMemUtils.putNativePtr(this, value.rawValue)
|
||||
|
||||
/**
|
||||
* The code or data pointed by the value of this variable.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline var <reified T : CPointed, reified P : CPointer<T>> CPointerVarOf<P>.pointed: T?
|
||||
get() = this.value?.pointed
|
||||
set(value) {
|
||||
this.value = value?.ptr as P?
|
||||
}
|
||||
|
||||
public inline operator fun <reified T : CVariable> CPointer<T>.get(index: Long): T {
|
||||
val offset = if (index == 0L) {
|
||||
0L // optimization for JVM impl which uses reflection for now.
|
||||
} else {
|
||||
index * sizeOf<T>()
|
||||
}
|
||||
return interpretPointed(this.rawValue + offset)
|
||||
}
|
||||
|
||||
public inline operator fun <reified T : CVariable> CPointer<T>.get(index: Int): T = this.get(index.toLong())
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("plus\$CPointer")
|
||||
public inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
|
||||
interpretCPointer(this.rawValue + index * pointerSize)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("plus\$CPointer")
|
||||
public inline operator fun <T : CPointerVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
|
||||
this + index.toLong()
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Int): T? =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Int, value: T?) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.get(index: Long): T? =
|
||||
(this + index)!!.pointed.value
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun <T : CPointer<*>> CPointer<CPointerVarOf<T>>.set(index: Long, value: T?) {
|
||||
(this + index)!!.pointed.value = value
|
||||
}
|
||||
|
||||
public typealias CArrayPointer<T> = CPointer<T>
|
||||
public typealias CArrayPointerVar<T> = CPointerVar<T>
|
||||
|
||||
/**
|
||||
* The C function.
|
||||
*/
|
||||
public class CFunction<T : Function<*>>(rawPtr: NativePtr) : CPointed(rawPtr)
|
||||
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
public interface NativePlacement {
|
||||
|
||||
public fun alloc(size: Long, align: Int): NativePointed
|
||||
|
||||
public fun alloc(size: Int, align: Int): NativePointed = alloc(size.toLong(), align)
|
||||
}
|
||||
|
||||
public interface NativeFreeablePlacement : NativePlacement {
|
||||
public fun free(mem: NativePtr)
|
||||
}
|
||||
|
||||
public fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue)
|
||||
public fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr)
|
||||
|
||||
public object nativeHeap : NativeFreeablePlacement {
|
||||
override fun alloc(size: Long, align: Int) = nativeMemUtils.alloc(size, align)
|
||||
|
||||
override fun free(mem: NativePtr) = nativeMemUtils.free(mem)
|
||||
}
|
||||
|
||||
private typealias Deferred = () -> Unit
|
||||
|
||||
public open class DeferScope {
|
||||
|
||||
@PublishedApi
|
||||
internal var topDeferred: Deferred? = null
|
||||
|
||||
internal fun executeAllDeferred() {
|
||||
topDeferred?.let {
|
||||
it.invoke()
|
||||
topDeferred = null
|
||||
}
|
||||
}
|
||||
|
||||
inline fun defer(crossinline block: () -> Unit) {
|
||||
val currentTop = topDeferred
|
||||
topDeferred = {
|
||||
try {
|
||||
block()
|
||||
} finally {
|
||||
// TODO: it is possible to implement chaining without recursion,
|
||||
// but it would require using an anonymous object here
|
||||
// which is not yet supported in Kotlin Native inliner.
|
||||
currentTop?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AutofreeScope : DeferScope(), NativePlacement {
|
||||
abstract override fun alloc(size: Long, align: Int): NativePointed
|
||||
}
|
||||
|
||||
public open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() {
|
||||
|
||||
private var lastChunk: NativePointed? = null
|
||||
|
||||
final override fun alloc(size: Long, align: Int): NativePointed {
|
||||
// Reserve space for a pointer:
|
||||
val gapForPointer = maxOf(pointerSize, align)
|
||||
|
||||
val chunk = parent.alloc(size = gapForPointer + size, align = gapForPointer)
|
||||
nativeMemUtils.putNativePtr(chunk, lastChunk.rawPtr)
|
||||
lastChunk = chunk
|
||||
return interpretOpaquePointed(chunk.rawPtr + gapForPointer.toLong())
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun clearImpl() {
|
||||
this.executeAllDeferred()
|
||||
|
||||
var chunk = lastChunk
|
||||
while (chunk != null) {
|
||||
val nextChunk = nativeMemUtils.getNativePtr(chunk)
|
||||
parent.free(chunk)
|
||||
chunk = interpretNullableOpaquePointed(nextChunk)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) {
|
||||
fun clear() = this.clearImpl()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates variable of given type.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.alloc(): T =
|
||||
@Suppress("DEPRECATION")
|
||||
alloc(typeOf<T>()).reinterpret()
|
||||
|
||||
@PublishedApi
|
||||
@Suppress("DEPRECATION")
|
||||
internal fun NativePlacement.alloc(type: CVariable.Type): NativePointed =
|
||||
alloc(type.size, type.align)
|
||||
|
||||
/**
|
||||
* Allocates variable of given type and initializes it applying given block.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.alloc(initialize: T.() -> Unit): T =
|
||||
alloc<T>().also { it.initialize() }
|
||||
|
||||
/**
|
||||
* Allocates C array of given elements type and length.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long): CArrayPointer<T> =
|
||||
alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret<T>().ptr
|
||||
|
||||
/**
|
||||
* Allocates C array of given elements type and length.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Int): CArrayPointer<T> =
|
||||
allocArray(length.toLong())
|
||||
|
||||
/**
|
||||
* Allocates C array of given elements type and length, and initializes its elements applying given block.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.allocArray(length: Long,
|
||||
initializer: T.(index: Long)->Unit): CArrayPointer<T> {
|
||||
val res = allocArray<T>(length)
|
||||
|
||||
(0 .. length - 1).forEach { index ->
|
||||
res[index].initializer(index)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates C array of given elements type and length, and initializes its elements applying given block.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
public inline fun <reified T : CVariable> NativePlacement.allocArray(
|
||||
length: Int, initializer: T.(index: Int)->Unit): CArrayPointer<T> = allocArray(length.toLong()) { index ->
|
||||
this.initializer(index.toInt())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocates C array of pointers to given elements.
|
||||
*/
|
||||
public fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(elements: List<T?>): CArrayPointer<CPointerVar<T>> {
|
||||
val res = allocArray<CPointerVar<T>>(elements.size)
|
||||
elements.forEachIndexed { index, value ->
|
||||
res[index] = value?.ptr
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates C array of pointers to given elements.
|
||||
*/
|
||||
public fun <T : CPointed> NativePlacement.allocArrayOfPointersTo(vararg elements: T?) =
|
||||
allocArrayOfPointersTo(listOf(*elements))
|
||||
|
||||
/**
|
||||
* Allocates C array of given values.
|
||||
*/
|
||||
public inline fun <reified T : CPointer<*>>
|
||||
NativePlacement.allocArrayOf(vararg elements: T?): CArrayPointer<CPointerVarOf<T>> {
|
||||
return allocArrayOf(listOf(*elements))
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates C array of given values.
|
||||
*/
|
||||
public inline fun <reified T : CPointer<*>>
|
||||
NativePlacement.allocArrayOf(elements: List<T?>): CArrayPointer<CPointerVarOf<T>> {
|
||||
|
||||
val res = allocArray<CPointerVarOf<T>>(elements.size)
|
||||
var index = 0
|
||||
while (index < elements.size) {
|
||||
res[index] = elements[index]
|
||||
++index
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
public fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer<ByteVar> {
|
||||
val result = allocArray<ByteVar>(elements.size)
|
||||
nativeMemUtils.putByteArray(elements, result.pointed, elements.size)
|
||||
return result
|
||||
}
|
||||
|
||||
public fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar> {
|
||||
val res = allocArray<FloatVar>(elements.size)
|
||||
var index = 0
|
||||
while (index < elements.size) {
|
||||
res[index] = elements[index]
|
||||
++index
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
public fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>()
|
||||
|
||||
@PublishedApi
|
||||
internal class ZeroValue<T: CVariable>(private val sizeBytes: Int, private val alignBytes: Int): CValue<T>() {
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<T> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
override fun place(placement: CPointer<T>): CPointer<T> {
|
||||
nativeMemUtils.zeroMemory(interpretPointed(placement.rawValue), sizeBytes)
|
||||
return placement
|
||||
}
|
||||
override val size get() = sizeBytes
|
||||
|
||||
override val align get() = alignBytes
|
||||
|
||||
}
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = ZeroValue(size, align)
|
||||
|
||||
public inline fun <reified T : CVariable> zeroValue(): CValue<T> = zeroValue<T>(sizeOf<T>().toInt(), alignOf<T>())
|
||||
|
||||
public inline fun <reified T : CVariable> cValue(): CValue<T> = zeroValue<T>()
|
||||
|
||||
public fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
|
||||
val bytes = ByteArray(size)
|
||||
nativeMemUtils.getByteArray(this, bytes, size)
|
||||
|
||||
return object : CValue<T>() {
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<T> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
override fun place(placement: CPointer<T>): CPointer<T> {
|
||||
nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size)
|
||||
return placement
|
||||
}
|
||||
override val size get() = size
|
||||
override val align get() = align
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <reified T : CVariable> T.readValues(count: Int): CValues<T> =
|
||||
this.readValues<T>(size = count * sizeOf<T>().toInt(), align = alignOf<T>())
|
||||
|
||||
public fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> {
|
||||
val bytes = ByteArray(size.toInt())
|
||||
nativeMemUtils.getByteArray(this, bytes, size.toInt())
|
||||
|
||||
return object : CValue<T>() {
|
||||
override fun place(placement: CPointer<T>): CPointer<T> {
|
||||
nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size)
|
||||
return placement
|
||||
}
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
public override fun getPointer(scope: AutofreeScope): CPointer<T> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
override val size get() = size.toInt()
|
||||
override val align get() = align
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@PublishedApi internal fun <T : CVariable> CPointed.readValue(type: CVariable.Type): CValue<T> =
|
||||
readValue(type.size, type.align)
|
||||
|
||||
// Note: can't be declared as property due to possible clash with a struct field.
|
||||
// TODO: find better name.
|
||||
@Suppress("DEPRECATION")
|
||||
public inline fun <reified T : CStructVar> T.readValue(): CValue<T> = this.readValue(typeOf<T>())
|
||||
|
||||
public fun <T: CVariable> CValue<T>.write(location: NativePtr) {
|
||||
this.place(interpretCPointer(location)!!)
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
public fun <T : CVariable> CValues<T>.getBytes(): ByteArray = memScoped {
|
||||
val result = ByteArray(size)
|
||||
nativeMemUtils.getByteArray(
|
||||
source = this@getBytes.placeTo(memScope).reinterpret<ByteVar>().pointed,
|
||||
dest = result,
|
||||
length = result.size
|
||||
)
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the [block] with temporary copy of this value as receiver.
|
||||
*/
|
||||
public inline fun <reified T : CStructVar, R> CValue<T>.useContents(block: T.() -> R): R = memScoped {
|
||||
this@useContents.placeTo(memScope).pointed.block()
|
||||
}
|
||||
|
||||
public inline fun <reified T : CStructVar> CValue<T>.copy(modify: T.() -> Unit): CValue<T> = useContents {
|
||||
this.modify()
|
||||
this.readValue()
|
||||
}
|
||||
|
||||
public inline fun <reified T : CStructVar> cValue(initialize: T.() -> Unit): CValue<T> =
|
||||
zeroValue<T>().copy(modify = initialize)
|
||||
|
||||
public inline fun <reified T : CVariable> createValues(count: Int, initializer: T.(index: Int) -> Unit) = memScoped {
|
||||
val array = allocArray<T>(count, initializer)
|
||||
array[0].readValues(count)
|
||||
}
|
||||
|
||||
// TODO: optimize other [cValuesOf] methods:
|
||||
/**
|
||||
* Returns sequence of immutable values [CValues] to pass them to C code.
|
||||
*/
|
||||
fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() {
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
override fun place(placement: CPointer<ByteVar>): CPointer<ByteVar> {
|
||||
nativeMemUtils.putByteArray(elements, interpretPointed(placement.rawValue), elements.size)
|
||||
return placement
|
||||
}
|
||||
|
||||
override val size get() = 1 * elements.size
|
||||
override val align get() = 1
|
||||
}
|
||||
|
||||
public fun cValuesOf(vararg elements: Short): CValues<ShortVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun cValuesOf(vararg elements: Int): CValues<IntVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun cValuesOf(vararg elements: Long): CValues<LongVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun cValuesOf(vararg elements: Float): CValues<FloatVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun cValuesOf(vararg elements: Double): CValues<DoubleVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun <T : CPointed> cValuesOf(vararg elements: CPointer<T>?): CValues<CPointerVar<T>> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
public fun ByteArray.toCValues() = cValuesOf(*this)
|
||||
public fun ShortArray.toCValues() = cValuesOf(*this)
|
||||
public fun IntArray.toCValues() = cValuesOf(*this)
|
||||
public fun LongArray.toCValues() = cValuesOf(*this)
|
||||
public fun FloatArray.toCValues() = cValuesOf(*this)
|
||||
public fun DoubleArray.toCValues() = cValuesOf(*this)
|
||||
public fun <T : CPointed> Array<CPointer<T>?>.toCValues() = cValuesOf(*this)
|
||||
public fun <T : CPointed> List<CPointer<T>?>.toCValues() = this.toTypedArray().toCValues()
|
||||
|
||||
private class CString(val bytes: ByteArray): CValues<ByteVar>() {
|
||||
override val size get() = bytes.size + 1
|
||||
override val align get() = 1
|
||||
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
override fun place(placement: CPointer<ByteVar>): CPointer<ByteVar> {
|
||||
nativeMemUtils.putByteArray(bytes, placement.pointed, bytes.size)
|
||||
placement[bytes.size] = 0.toByte()
|
||||
return placement
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.cstr: CValues<ByteVar>
|
||||
get() = CString(encodeToUtf8(this))
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf8: CValues<ByteVar>
|
||||
get() = CString(encodeToUtf8(this))
|
||||
|
||||
/**
|
||||
* Convert this list of Kotlin strings to C array of C strings,
|
||||
* allocating memory for the array and C strings with given [AutofreeScope].
|
||||
*/
|
||||
public fun List<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> =
|
||||
autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) })
|
||||
|
||||
/**
|
||||
* Convert this array of Kotlin strings to C array of C strings,
|
||||
* allocating memory for the array and C strings with given [AutofreeScope].
|
||||
*/
|
||||
public fun Array<String>.toCStringArray(autofreeScope: AutofreeScope): CPointer<CPointerVar<ByteVar>> =
|
||||
autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) })
|
||||
|
||||
|
||||
private class U16CString(val chars: CharArray): CValues<UShortVar>() {
|
||||
override val size get() = 2 * (chars.size + 1)
|
||||
|
||||
override val align get() = 2
|
||||
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<UShortVar> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
override fun place(placement: CPointer<UShortVar>): CPointer<UShortVar> {
|
||||
nativeMemUtils.putCharArray(chars, placement.pointed, chars.size)
|
||||
// TODO: fix, after KT-29627 is fixed.
|
||||
nativeMemUtils.putShort((placement + chars.size)!!.pointed, 0)
|
||||
return placement
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-16-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.wcstr: CValues<UShortVar>
|
||||
get() = U16CString(this.toCharArray())
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-16-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf16: CValues<UShortVar>
|
||||
get() = U16CString(this.toCharArray())
|
||||
|
||||
private class U32CString(val chars: CharArray): CValues<IntVar>() {
|
||||
override val size get() = 4 * (chars.size + 1)
|
||||
|
||||
override val align get() = 4
|
||||
|
||||
// Optimization to avoid unneeded virtual calls in base class implementation.
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<IntVar> {
|
||||
return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!)
|
||||
}
|
||||
|
||||
override fun place(placement: CPointer<IntVar>): CPointer<IntVar> {
|
||||
var indexIn = 0
|
||||
var indexOut = 0
|
||||
while (indexIn < chars.size) {
|
||||
var value = chars[indexIn++].toInt()
|
||||
if (value >= 0xd800 && value < 0xdc00) {
|
||||
// Surrogate pair.
|
||||
if (indexIn >= chars.size - 1) throw IllegalArgumentException()
|
||||
indexIn++
|
||||
val next = chars[indexIn].toInt()
|
||||
if (next < 0xdc00 || next >= 0xe000) throw IllegalArgumentException()
|
||||
value = 0x10000 + ((value and 0x3ff) shl 10) + (next and 0x3ff)
|
||||
}
|
||||
nativeMemUtils.putInt((placement + indexOut)!!.pointed, value)
|
||||
indexOut++
|
||||
}
|
||||
nativeMemUtils.putInt((placement + indexOut)!!.pointed, 0)
|
||||
return placement
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of zero-terminated UTF-32-encoded C string constructed from given [kotlin.String].
|
||||
*/
|
||||
public val String.utf32: CValues<IntVar>
|
||||
get() = U32CString(this.toCharArray())
|
||||
|
||||
|
||||
// TODO: optimize
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string.
|
||||
*/
|
||||
public fun CPointer<ByteVar>.toKStringFromUtf8(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toByte()) {
|
||||
++length
|
||||
}
|
||||
|
||||
val bytes = ByteArray(length)
|
||||
nativeMemUtils.getByteArray(nativeBytes.pointed, bytes, length)
|
||||
return decodeFromUtf8(bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string.
|
||||
*/
|
||||
public fun CPointer<ByteVar>.toKString(): String = this.toKStringFromUtf8()
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-16-encoded C string.
|
||||
*/
|
||||
public fun CPointer<ShortVar>.toKStringFromUtf16(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toShort()) {
|
||||
++length
|
||||
}
|
||||
val chars = CharArray(length)
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
chars[index] = nativeBytes[index].toChar()
|
||||
++index
|
||||
}
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [kotlin.String] decoded from given zero-terminated UTF-32-encoded C string.
|
||||
*/
|
||||
public fun CPointer<IntVar>.toKStringFromUtf32(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var fromIndex = 0
|
||||
var toIndex = 0
|
||||
while (true) {
|
||||
val value = nativeBytes[fromIndex++]
|
||||
if (value == 0) break
|
||||
toIndex++
|
||||
if (value >= 0x10000 && value <= 0x10ffff) {
|
||||
toIndex++
|
||||
}
|
||||
}
|
||||
val length = toIndex
|
||||
val chars = CharArray(length)
|
||||
fromIndex = 0
|
||||
toIndex = 0
|
||||
while (toIndex < length) {
|
||||
var value = nativeBytes[fromIndex++]
|
||||
if (value >= 0x10000 && value <= 0x10ffff) {
|
||||
chars[toIndex++] = (((value - 0x10000) shr 10) or 0xd800).toChar()
|
||||
chars[toIndex++] = (((value - 0x10000) and 0x3ff) or 0xdc00).toChar()
|
||||
} else {
|
||||
chars[toIndex++] = value.toChar()
|
||||
}
|
||||
}
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string from the bytes in UTF-8 encoding in this array.
|
||||
* Bytes following the first occurrence of `0` byte, if it occurs, are not decoded.
|
||||
*
|
||||
* Malformed byte sequences are replaced by the replacement char `\uFFFD`.
|
||||
*/
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@SinceKotlin("1.3")
|
||||
public fun ByteArray.toKString() : String {
|
||||
val realEndIndex = realEndIndex(this, 0, this.size)
|
||||
return decodeToString(0, realEndIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string from the bytes in UTF-8 encoding in this array or its subrange.
|
||||
* Bytes following the first occurrence of `0` byte, if it occurs, are not decoded.
|
||||
*
|
||||
* @param startIndex the beginning (inclusive) of the subrange to decode, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the subrange to decode, size of this array by default.
|
||||
* @param throwOnInvalidSequence specifies whether to throw an exception on malformed byte sequence or replace it by the replacement char `\uFFFD`.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the size of this array.
|
||||
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
|
||||
* @throws CharacterCodingException if the byte array contains malformed UTF-8 byte sequence and [throwOnInvalidSequence] is true.
|
||||
*/
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@SinceKotlin("1.3")
|
||||
public fun ByteArray.toKString(
|
||||
startIndex: Int = 0,
|
||||
endIndex: Int = this.size,
|
||||
throwOnInvalidSequence: Boolean = false
|
||||
) : String {
|
||||
checkBoundsIndexes(startIndex, endIndex, this.size)
|
||||
val realEndIndex = realEndIndex(this, startIndex, endIndex)
|
||||
return decodeToString(startIndex, realEndIndex, throwOnInvalidSequence)
|
||||
}
|
||||
|
||||
private fun realEndIndex(byteArray: ByteArray, startIndex: Int, endIndex: Int): Int {
|
||||
var index = startIndex
|
||||
while (index < endIndex && byteArray[index] != 0.toByte()) {
|
||||
index++
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
private fun checkBoundsIndexes(startIndex: Int, endIndex: Int, size: Int) {
|
||||
if (startIndex < 0 || endIndex > size) {
|
||||
throw IndexOutOfBoundsException("startIndex: $startIndex, endIndex: $endIndex, size: $size")
|
||||
}
|
||||
if (startIndex > endIndex) {
|
||||
throw IllegalArgumentException("startIndex: $startIndex > endIndex: $endIndex")
|
||||
}
|
||||
}
|
||||
|
||||
public class MemScope : ArenaBase() {
|
||||
|
||||
val memScope: MemScope
|
||||
get() = this
|
||||
|
||||
val <T: CVariable> CValues<T>.ptr: CPointer<T>
|
||||
get() = this@ptr.getPointer(this@MemScope)
|
||||
}
|
||||
|
||||
// TODO: consider renaming `memScoped` because it now supports `defer`.
|
||||
|
||||
/**
|
||||
* Runs given [block] providing allocation of memory
|
||||
* which will be automatically disposed at the end of this scope.
|
||||
*/
|
||||
public inline fun <R> memScoped(block: MemScope.()->R): R {
|
||||
val memScope = MemScope()
|
||||
try {
|
||||
return memScope.block()
|
||||
} finally {
|
||||
memScope.clearImpl()
|
||||
}
|
||||
}
|
||||
|
||||
public fun COpaquePointer.readBytes(count: Int): ByteArray {
|
||||
val result = ByteArray(count)
|
||||
nativeMemUtils.getByteArray(this.reinterpret<ByteVar>().pointed, result, count)
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains API and runtime support for calling C code from Kotlin (aka Kotlin C interop).
|
||||
*
|
||||
* TODO: decide about package location.
|
||||
*/
|
||||
package kotlinx.cinterop;
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
|
||||
public class ForeignException internal constructor(val nativeException: Any?): Exception() {
|
||||
override val message: String = nativeException?.let {
|
||||
kotlin_ObjCExport_ExceptionDetails(nativeException)
|
||||
}?: ""
|
||||
|
||||
// Current implementation expects NSException type only, which is ensured by CodeGenerator.
|
||||
@SymbolName("Kotlin_ObjCExport_ExceptionDetails")
|
||||
private external fun kotlin_ObjCExport_ExceptionDetails(nativeException: Any): String?
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun CreateForeignException(payload: NativePtr): Throwable
|
||||
= ForeignException(interpretObjCPointerOrNull<Any?>(payload))
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
import kotlin.native.internal.ExportForCompiler
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <R> CPointer<CFunction<() -> R>>.invoke(): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, R> CPointer<CFunction<(P1) -> R>>.invoke(p1: P1): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, R> CPointer<CFunction<(P1, P2) -> R>>.invoke(p1: P1, p2: P2): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, R> CPointer<CFunction<(P1, P2, P3) -> R>>.invoke(p1: P1, p2: P2, p3: P3): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, R> CPointer<CFunction<(P1, P2, P3, P4) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, R> CPointer<CFunction<(P1, P2, P3, P4, P5) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_FUNPTR_INVOKE) external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@PublishedApi
|
||||
internal inline val pointerSize: Int
|
||||
get() = getPointerSize()
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_GET_POINTER_SIZE)
|
||||
internal external fun getPointerSize(): Int
|
||||
|
||||
// TODO: do not use singleton because it leads to init-check on any access.
|
||||
@PublishedApi
|
||||
internal object nativeMemUtils {
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getByte(mem: NativePointed): Byte
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putByte(mem: NativePointed, value: Byte)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getShort(mem: NativePointed): Short
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putShort(mem: NativePointed, value: Short)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getInt(mem: NativePointed): Int
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putInt(mem: NativePointed, value: Int)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getLong(mem: NativePointed): Long
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putLong(mem: NativePointed, value: Long)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getFloat(mem: NativePointed): Float
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putFloat(mem: NativePointed, value: Float)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getDouble(mem: NativePointed): Double
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putDouble(mem: NativePointed, value: Double)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getNativePtr(mem: NativePointed): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putNativePtr(mem: NativePointed, value: NativePtr)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getVector(mem: NativePointed): Vector128
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putVector(mem: NativePointed, value: Vector128)
|
||||
|
||||
// TODO: optimize
|
||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||
val sourceArray = source.reinterpret<ByteVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
dest[index] = sourceArray[index]
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) {
|
||||
val destArray = dest.reinterpret<ByteVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
destArray[index] = source[index]
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun getCharArray(source: NativePointed, dest: CharArray, length: Int) {
|
||||
val sourceArray = source.reinterpret<ShortVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
dest[index] = sourceArray[index].toChar()
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun putCharArray(source: CharArray, dest: NativePointed, length: Int) {
|
||||
val destArray = dest.reinterpret<ShortVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
destArray[index] = source[index].toShort()
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun zeroMemory(dest: NativePointed, length: Int): Unit {
|
||||
val destArray = dest.reinterpret<ByteVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
destArray[index] = 0
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
fun copyMemory(dest: NativePointed, length: Int, src: NativePointed): Unit {
|
||||
val destArray = dest.reinterpret<ByteVar>().ptr
|
||||
val srcArray = src.reinterpret<ByteVar>().ptr
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
destArray[index] = srcArray[index]
|
||||
++index
|
||||
}
|
||||
}
|
||||
|
||||
fun alloc(size: Long, align: Int): NativePointed {
|
||||
val ptr = malloc(size, align)
|
||||
if (ptr == nativeNullPtr) {
|
||||
throw OutOfMemoryError("unable to allocate native memory")
|
||||
}
|
||||
return interpretOpaquePointed(ptr)
|
||||
}
|
||||
|
||||
fun free(mem: NativePtr) {
|
||||
cfree(mem)
|
||||
}
|
||||
}
|
||||
|
||||
public fun CPointer<UShortVar>.toKStringFromUtf16(): String {
|
||||
val nativeBytes = this
|
||||
|
||||
var length = 0
|
||||
while (nativeBytes[length] != 0.toUShort()) {
|
||||
++length
|
||||
}
|
||||
val chars = kotlin.CharArray(length)
|
||||
var index = 0
|
||||
while (index < length) {
|
||||
chars[index] = nativeBytes[index].toShort().toChar()
|
||||
++index
|
||||
}
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
public fun CPointer<ShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
public fun CPointer<UShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
@SymbolName("Kotlin_interop_malloc")
|
||||
private external fun malloc(size: Long, align: Int): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_interop_free")
|
||||
private external fun cfree(ptr: NativePtr)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS)
|
||||
external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_BITS)
|
||||
external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long)
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
|
||||
@SymbolName("Kotlin_Interop_createStablePointer")
|
||||
internal external fun createStablePointer(any: Any): COpaquePointer
|
||||
|
||||
@SymbolName("Kotlin_Interop_disposeStablePointer")
|
||||
internal external fun disposeStablePointer(pointer: COpaquePointer)
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Interop_derefStablePointer")
|
||||
internal external fun derefStablePointer(pointer: COpaquePointer): Any
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.getNativeNullPtr
|
||||
import kotlin.native.internal.reinterpret
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.VolatileLambda
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
typealias NativePtr = kotlin.native.internal.NativePtr
|
||||
internal typealias NonNullNativePtr = kotlin.native.internal.NonNullNativePtr
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun NativePtr.toNonNull() = this.reinterpret<NativePtr, NonNullNativePtr>()
|
||||
|
||||
inline val nativeNullPtr: NativePtr
|
||||
get() = getNativeNullPtr()
|
||||
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
fun <T : CVariable> typeOf(): CVariable.Type = throw Error("typeOf() is called with erased argument")
|
||||
|
||||
/**
|
||||
* Performs type cast of the native pointer to given interop type, including null values.
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun <T : NativePointed> interpretNullablePointed(ptr: NativePtr): T?
|
||||
|
||||
/**
|
||||
* Performs type cast of the [CPointer] from the given raw pointer.
|
||||
*/
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun <T : CPointed> interpretCPointer(rawValue: NativePtr): CPointer<T>?
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun NativePointed.getRawPointer(): NativePtr
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun CPointer<*>.getRawValue(): NativePtr
|
||||
|
||||
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)"
|
||||
|
||||
public class Vector128VarOf<T : Vector128>(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : Type(size = 16, align = 16)
|
||||
}
|
||||
|
||||
public typealias Vector128Var = Vector128VarOf<Vector128>
|
||||
|
||||
public var <T : Vector128> Vector128VarOf<T>.value: T
|
||||
get() = nativeMemUtils.getVector(this) as T
|
||||
set(value) = nativeMemUtils.putVector(this, value)
|
||||
|
||||
/**
|
||||
* Returns a pointer to C function which calls given Kotlin *static* function.
|
||||
*
|
||||
* @param function must be *static*, i.e. an (unbound) reference to a Kotlin function or
|
||||
* a closure which doesn't capture any variable
|
||||
*/
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <R> staticCFunction(@VolatileLambda function: () -> R): CPointer<CFunction<() -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, R> staticCFunction(@VolatileLambda function: (P1) -> R): CPointer<CFunction<(P1) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, R> staticCFunction(@VolatileLambda function: (P1, P2) -> R): CPointer<CFunction<(P1, P2) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, R> staticCFunction(@VolatileLambda function: (P1, P2, P3) -> R): CPointer<CFunction<(P1, P2, P3) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4) -> R): CPointer<CFunction<(P1, P2, P3, P4) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>>
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
internal fun decodeFromUtf8(bytes: ByteArray): String = bytes.decodeToString()
|
||||
internal fun encodeToUtf8(str: String): ByteArray = str.encodeToByteArray()
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_BITS_TO_FLOAT)
|
||||
external fun bitsToFloat(bits: Int): Float
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_BITS_TO_DOUBLE)
|
||||
external fun bitsToDouble(bits: Long): Double
|
||||
|
||||
// TODO: deprecate.
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_SIGN_EXTEND)
|
||||
external inline fun <reified R : Number> Number.signExtend(): R
|
||||
|
||||
// TODO: deprecate.
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_NARROW)
|
||||
external inline fun <reified R : Number> Number.narrow(): R
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> Byte.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> Short.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> Int.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> Long.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> UByte.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> UShort.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> UInt.convert(): R
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_CONVERT) external inline fun <reified R : Any> ULong.convert(): R
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FILE)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
internal annotation class JvmName(val name: String)
|
||||
|
||||
fun cValuesOf(vararg elements: UByte): CValues<UByteVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
fun cValuesOf(vararg elements: UShort): CValues<UShortVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
fun cValuesOf(vararg elements: UInt): CValues<UIntVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
fun cValuesOf(vararg elements: ULong): CValues<ULongVar> =
|
||||
createValues(elements.size) { index -> this.value = elements[index] }
|
||||
|
||||
fun UByteArray.toCValues() = cValuesOf(*this)
|
||||
fun UShortArray.toCValues() = cValuesOf(*this)
|
||||
fun UIntArray.toCValues() = cValuesOf(*this)
|
||||
fun ULongArray.toCValues() = cValuesOf(*this)
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
import kotlin.native.internal.FilterExceptions
|
||||
|
||||
interface ObjCObject
|
||||
interface ObjCClass : ObjCObject
|
||||
interface ObjCClassOf<T : ObjCObject> : ObjCClass // TODO: T should be added to ObjCClass and all meta-classes instead.
|
||||
typealias ObjCObjectMeta = ObjCClass
|
||||
|
||||
interface ObjCProtocol : ObjCObject
|
||||
|
||||
@ExportTypeInfo("theForeignObjCObjectTypeInfo")
|
||||
@kotlin.native.internal.Frozen
|
||||
internal open class ForeignObjCObject : kotlin.native.internal.ObjCObjectWrapper
|
||||
|
||||
abstract class ObjCObjectBase protected constructor() : ObjCObject {
|
||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class OverrideInit
|
||||
}
|
||||
abstract class ObjCObjectBaseMeta protected constructor() : ObjCObjectBase(), ObjCObjectMeta {}
|
||||
|
||||
fun optional(): Nothing = throw RuntimeException("Do not call me!!!")
|
||||
|
||||
@Deprecated(
|
||||
"Add @OverrideInit to constructor to make it override Objective-C initializer",
|
||||
level = DeprecationLevel.ERROR
|
||||
)
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_INIT_BY)
|
||||
external fun <T : ObjCObjectBase> T.initBy(constructorCall: T): T
|
||||
|
||||
@kotlin.native.internal.ExportForCompiler
|
||||
private fun ObjCObjectBase.superInitCheck(superInitCallResult: ObjCObject?) {
|
||||
if (superInitCallResult == null)
|
||||
throw RuntimeException("Super initialization failed")
|
||||
|
||||
if (superInitCallResult.objcPtr() != this.objcPtr())
|
||||
throw UnsupportedOperationException("Super initializer has replaced object")
|
||||
}
|
||||
|
||||
internal fun <T : Any?> Any?.uncheckedCast(): T = @Suppress("UNCHECKED_CAST") (this as T)
|
||||
|
||||
// Note: if this is called for non-frozen object on a wrong worker, the program will terminate.
|
||||
@SymbolName("Kotlin_Interop_refFromObjC")
|
||||
external fun <T> interpretObjCPointerOrNull(objcPtr: NativePtr): T?
|
||||
|
||||
@ExportForCppRuntime
|
||||
inline fun <T : Any> interpretObjCPointer(objcPtr: NativePtr): T = interpretObjCPointerOrNull<T>(objcPtr)!!
|
||||
|
||||
@SymbolName("Kotlin_Interop_refToObjC")
|
||||
external fun Any?.objcPtr(): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_Interop_createKotlinObjectHolder")
|
||||
external fun createKotlinObjectHolder(any: Any?): NativePtr
|
||||
|
||||
// Note: if this is called for non-frozen underlying ref on a wrong worker, the program will terminate.
|
||||
inline fun <reified T : Any> unwrapKotlinObjectHolder(holder: Any?): T {
|
||||
return unwrapKotlinObjectHolderImpl(holder!!.objcPtr()) as T
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Interop_unwrapKotlinObjectHolder")
|
||||
external internal fun unwrapKotlinObjectHolderImpl(ptr: NativePtr): Any
|
||||
|
||||
class ObjCObjectVar<T>(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : CVariable.Type(pointerSize.toLong(), pointerSize)
|
||||
}
|
||||
|
||||
class ObjCNotImplementedVar<T : Any?>(rawPtr: NativePtr) : CVariable(rawPtr) {
|
||||
@Deprecated("Use sizeOf<T>() or alignOf<T>() instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
companion object : CVariable.Type(pointerSize.toLong(), pointerSize)
|
||||
}
|
||||
|
||||
var <T : Any?> ObjCNotImplementedVar<T>.value: T
|
||||
get() = TODO()
|
||||
set(value) = TODO()
|
||||
|
||||
typealias ObjCStringVarOf<T> = ObjCNotImplementedVar<T>
|
||||
typealias ObjCBlockVar<T> = ObjCNotImplementedVar<T>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_CREATE_SUPER_STRUCT)
|
||||
@PublishedApi
|
||||
internal external fun createObjCSuperStruct(receiver: NativePtr, superClass: NativePtr): NativePtr
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ExternalObjCClass(val protocolGetter: String = "", val binaryName: String = "")
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ObjCMethod(val selector: String, val encoding: String, val isStret: Boolean = false)
|
||||
|
||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ObjCConstructor(val initSelector: String, val designated: Boolean)
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ObjCFactory(val selector: String, val encoding: String, val isStret: Boolean = false)
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class InteropStubs()
|
||||
|
||||
@PublishedApi
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
internal annotation class ObjCMethodImp(val selector: String, val encoding: String)
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_SELECTOR)
|
||||
internal external fun objCGetSelector(selector: String): COpaquePointer
|
||||
|
||||
@kotlin.native.internal.ExportForCppRuntime("Kotlin_Interop_getObjCClass")
|
||||
private fun getObjCClassByName(name: NativePtr): NativePtr {
|
||||
val result = objc_lookUpClass(name)
|
||||
if (result == nativeNullPtr) {
|
||||
val className = interpretCPointer<ByteVar>(name)!!.toKString()
|
||||
val message = """Objective-C class '$className' not found.
|
||||
|Ensure that the containing framework or library was linked.""".trimMargin()
|
||||
|
||||
throw RuntimeException(message)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@kotlin.native.internal.ExportForCompiler
|
||||
private fun allocObjCObject(clazz: NativePtr): NativePtr {
|
||||
val rawResult = objc_allocWithZone(clazz)
|
||||
if (rawResult == nativeNullPtr) {
|
||||
throw OutOfMemoryError("Unable to allocate Objective-C object")
|
||||
}
|
||||
|
||||
// Note: `objc_allocWithZone` returns retained pointer, and thus it must be balanced by the caller.
|
||||
|
||||
return rawResult
|
||||
}
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_OBJC_CLASS)
|
||||
@kotlin.native.internal.ExportForCompiler
|
||||
private external fun <T : ObjCObject> getObjCClass(): NativePtr
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER)
|
||||
internal external fun getMessenger(superClass: NativePtr): COpaquePointer?
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER_STRET)
|
||||
internal external fun getMessengerStret(superClass: NativePtr): COpaquePointer?
|
||||
|
||||
|
||||
internal class ObjCWeakReferenceImpl : kotlin.native.ref.WeakReferenceImpl() {
|
||||
@SymbolName("Konan_ObjCInterop_getWeakReference")
|
||||
external override fun get(): Any?
|
||||
}
|
||||
|
||||
@SymbolName("Konan_ObjCInterop_initWeakReference")
|
||||
private external fun ObjCWeakReferenceImpl.init(objcPtr: NativePtr)
|
||||
|
||||
@kotlin.native.internal.ExportForCppRuntime internal fun makeObjCWeakReferenceImpl(objcPtr: NativePtr): ObjCWeakReferenceImpl {
|
||||
val result = ObjCWeakReferenceImpl()
|
||||
result.init(objcPtr)
|
||||
return result
|
||||
}
|
||||
|
||||
// Konan runtme:
|
||||
|
||||
@Deprecated("Use plain Kotlin cast of String to NSString", level = DeprecationLevel.ERROR)
|
||||
@SymbolName("Kotlin_Interop_CreateNSStringFromKString")
|
||||
external fun CreateNSStringFromKString(str: String?): NativePtr
|
||||
|
||||
@Deprecated("Use plain Kotlin cast of NSString to String", level = DeprecationLevel.ERROR)
|
||||
@SymbolName("Kotlin_Interop_CreateKStringFromNSString")
|
||||
external fun CreateKStringFromNSString(ptr: NativePtr): String?
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Interop_CreateObjCObjectHolder")
|
||||
internal external fun createObjCObjectHolder(ptr: NativePtr): Any?
|
||||
|
||||
// Objective-C runtime:
|
||||
|
||||
@SymbolName("objc_retainAutoreleaseReturnValue")
|
||||
external fun objc_retainAutoreleaseReturnValue(ptr: NativePtr): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_objc_autoreleasePoolPush")
|
||||
external fun objc_autoreleasePoolPush(): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_objc_autoreleasePoolPop")
|
||||
external fun objc_autoreleasePoolPop(ptr: NativePtr)
|
||||
|
||||
@SymbolName("Kotlin_objc_allocWithZone")
|
||||
@FilterExceptions
|
||||
private external fun objc_allocWithZone(clazz: NativePtr): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_objc_retain")
|
||||
external fun objc_retain(ptr: NativePtr): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_objc_release")
|
||||
external fun objc_release(ptr: NativePtr)
|
||||
|
||||
@SymbolName("Kotlin_objc_lookUpClass")
|
||||
external fun objc_lookUpClass(name: NativePtr): NativePtr
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.KClassImpl
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* If [objCClass] is a class generated to Objective-C header for Kotlin class,
|
||||
* returns [KClass] for that original Kotlin class.
|
||||
*
|
||||
* Otherwise returns `null`.
|
||||
*/
|
||||
fun getOriginalKotlinClass(objCClass: ObjCClass): KClass<*>? {
|
||||
val typeInfo = getTypeInfoForClass(objCClass.objcPtr())
|
||||
if (typeInfo.isNull()) return null
|
||||
|
||||
return KClassImpl<Any>(typeInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* If [objCProtocol] is a protocol generated to Objective-C header for Kotlin class,
|
||||
* returns [KClass] for that original Kotlin class.
|
||||
*
|
||||
* Otherwise returns `null`.
|
||||
*/
|
||||
fun getOriginalKotlinClass(objCProtocol: ObjCProtocol): KClass<*>? {
|
||||
val typeInfo = getTypeInfoForProtocol(objCProtocol.objcPtr())
|
||||
if (typeInfo.isNull()) return null
|
||||
|
||||
return KClassImpl<Any>(typeInfo)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForClass")
|
||||
private external fun getTypeInfoForClass(ptr: NativePtr): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForProtocol")
|
||||
private external fun getTypeInfoForProtocol(ptr: NativePtr): NativePtr
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
inline fun <R> autoreleasepool(block: () -> R): R {
|
||||
val pool = objc_autoreleasePoolPush()
|
||||
return try {
|
||||
block()
|
||||
} finally {
|
||||
objc_autoreleasePoolPop(pool)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Use plain Kotlin cast", ReplaceWith("this as T"), DeprecationLevel.ERROR)
|
||||
fun <T : ObjCObject> ObjCObject.reinterpret() = @Suppress("DEPRECATION") this.uncheckedCast<T>()
|
||||
|
||||
// TODO: null checks
|
||||
var <T> ObjCObjectVar<T>.value: T
|
||||
@Suppress("DEPRECATION") get() =
|
||||
interpretObjCPointerOrNull<T>(nativeMemUtils.getNativePtr(this)).uncheckedCast<T>()
|
||||
|
||||
set(value) = nativeMemUtils.putNativePtr(this, value.objcPtr())
|
||||
|
||||
/**
|
||||
* Makes Kotlin method in Objective-C class accessible through Objective-C dispatch
|
||||
* to be used as action sent by control in UIKit or AppKit.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ObjCAction
|
||||
|
||||
/**
|
||||
* Makes Kotlin property in Objective-C class settable through Objective-C dispatch
|
||||
* to be used as IB outlet.
|
||||
*/
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ObjCOutlet
|
||||
|
||||
/**
|
||||
* Makes Kotlin subclass of Objective-C class visible for runtime lookup
|
||||
* after Kotlin `main` function gets invoked.
|
||||
*
|
||||
* Note: runtime lookup can be forced even when the class is referenced statically from
|
||||
* Objective-C source code by adding `__attribute__((objc_runtime_visible))` to its `@interface`.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ExportObjCClass(val name: String = "")
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
|
||||
data class Pinned<out T : Any> internal constructor(private val stablePtr: COpaquePointer) {
|
||||
|
||||
/**
|
||||
* Disposes the handle. It must not be [used][get] after that.
|
||||
*/
|
||||
fun unpin() {
|
||||
disposeStablePointer(this.stablePtr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying pinned object.
|
||||
*/
|
||||
fun get(): T = @Suppress("UNCHECKED_CAST") (derefStablePointer(stablePtr) as T)
|
||||
|
||||
}
|
||||
|
||||
fun <T : Any> T.pin() = Pinned<T>(createStablePointer(this))
|
||||
|
||||
inline fun <T : Any, R> T.usePinned(block: (Pinned<T>) -> R): R {
|
||||
val pinned = this.pin()
|
||||
return try {
|
||||
block(pinned)
|
||||
} finally {
|
||||
pinned.unpin()
|
||||
}
|
||||
}
|
||||
|
||||
fun Pinned<ByteArray>.addressOf(index: Int): CPointer<ByteVar> = this.get().addressOfElement(index)
|
||||
fun ByteArray.refTo(index: Int): CValuesRef<ByteVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<String>.addressOf(index: Int): CPointer<COpaque> = this.get().addressOfElement(index)
|
||||
fun String.refTo(index: Int): CValuesRef<COpaque> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<CharArray>.addressOf(index: Int): CPointer<COpaque> = this.get().addressOfElement(index)
|
||||
fun CharArray.refTo(index: Int): CValuesRef<COpaque> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<ShortArray>.addressOf(index: Int): CPointer<ShortVar> = this.get().addressOfElement(index)
|
||||
fun ShortArray.refTo(index: Int): CValuesRef<ShortVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<IntArray>.addressOf(index: Int): CPointer<IntVar> = this.get().addressOfElement(index)
|
||||
fun IntArray.refTo(index: Int): CValuesRef<IntVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<LongArray>.addressOf(index: Int): CPointer<LongVar> = this.get().addressOfElement(index)
|
||||
fun LongArray.refTo(index: Int): CValuesRef<LongVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
// TODO: pinning of unsigned arrays involves boxing as they are inline classes wrapping signed arrays.
|
||||
fun Pinned<UByteArray>.addressOf(index: Int): CPointer<UByteVar> = this.get().addressOfElement(index)
|
||||
fun UByteArray.refTo(index: Int): CValuesRef<UByteVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<UShortArray>.addressOf(index: Int): CPointer<UShortVar> = this.get().addressOfElement(index)
|
||||
fun UShortArray.refTo(index: Int): CValuesRef<UShortVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<UIntArray>.addressOf(index: Int): CPointer<UIntVar> = this.get().addressOfElement(index)
|
||||
fun UIntArray.refTo(index: Int): CValuesRef<UIntVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<ULongArray>.addressOf(index: Int): CPointer<ULongVar> = this.get().addressOfElement(index)
|
||||
fun ULongArray.refTo(index: Int): CValuesRef<ULongVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<FloatArray>.addressOf(index: Int): CPointer<FloatVar> = this.get().addressOfElement(index)
|
||||
fun FloatArray.refTo(index: Int): CValuesRef<FloatVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
fun Pinned<DoubleArray>.addressOf(index: Int): CPointer<DoubleVar> = this.get().addressOfElement(index)
|
||||
fun DoubleArray.refTo(index: Int): CValuesRef<DoubleVar> = this.usingPinned { addressOf(index) }
|
||||
|
||||
private inline fun <T : Any, P : CPointed> T.usingPinned(
|
||||
crossinline block: Pinned<T>.() -> CPointer<P>
|
||||
) = object : CValuesRef<P>() {
|
||||
|
||||
override fun getPointer(scope: AutofreeScope): CPointer<P> {
|
||||
val pinned = this@usingPinned.pin()
|
||||
scope.defer { pinned.unpin() }
|
||||
return pinned.block()
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
private external fun ByteArray.addressOfElement(index: Int): CPointer<ByteVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getStringAddressOfElement")
|
||||
private external fun String.addressOfElement(index: Int): CPointer<COpaque>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getCharArrayAddressOfElement")
|
||||
private external fun CharArray.addressOfElement(index: Int): CPointer<COpaque>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
private external fun ShortArray.addressOfElement(index: Int): CPointer<ShortVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
private external fun IntArray.addressOfElement(index: Int): CPointer<IntVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
private external fun LongArray.addressOfElement(index: Int): CPointer<LongVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
private external fun UByteArray.addressOfElement(index: Int): CPointer<UByteVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
private external fun UShortArray.addressOfElement(index: Int): CPointer<UShortVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
private external fun UIntArray.addressOfElement(index: Int): CPointer<UIntVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
private external fun ULongArray.addressOfElement(index: Int): CPointer<ULongVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getFloatArrayAddressOfElement")
|
||||
private external fun FloatArray.addressOfElement(index: Int): CPointer<FloatVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getDoubleArrayAddressOfElement")
|
||||
private external fun DoubleArray.addressOfElement(index: Int): CPointer<DoubleVar>
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package kotlinx.cinterop.internal
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class CStruct(val spelling: String) {
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
annotation class MemberAt(val offset: Long)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.PROPERTY_GETTER)
|
||||
annotation class ArrayMemberAt(val offset: Long)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
annotation class BitField(val offset: Long, val size: Int)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class VarType(val size: Long, val align: Int)
|
||||
}
|
||||
|
||||
@Target(
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
public annotation class CCall(val id: String) {
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class CString
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class WCString
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ReturnsRetained
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ConsumesReceiver
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Consumed
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection of annotations that allow to store
|
||||
* constant values.
|
||||
*/
|
||||
public object ConstantValue {
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Byte(val value: kotlin.Byte)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Short(val value: kotlin.Short)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Int(val value: kotlin.Int)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Long(val value: kotlin.Long)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class UByte(val value: kotlin.UByte)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class UShort(val value: kotlin.UShort)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class UInt(val value: kotlin.UInt)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ULong(val value: kotlin.ULong)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Float(val value: kotlin.Float)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class Double(val value: kotlin.Double)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class String(val value: kotlin.String)
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes property that is an alias to some enum entry.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
public annotation class CEnumEntryAlias(val entryName: String)
|
||||
|
||||
/**
|
||||
* Stores instance size of the type T: CEnumVar.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
public annotation class CEnumVarTypeSize(val size: Int)
|
||||
Reference in New Issue
Block a user