Improve StableObjPtr
* Rename to StableRef * Make it more typed * Provide more idiomatic and convenient methods * Share more code between JVM and Native
This commit is contained in:
committed by
SvyatoslavScherbina
parent
d8ed1f4414
commit
9609a10e09
+15
-16
@@ -138,16 +138,15 @@ internal fun CXTranslationUnit.ensureNoCompileErrors(): CXTranslationUnit {
|
|||||||
internal typealias CursorVisitor = (cursor: CValue<CXCursor>, parent: CValue<CXCursor>) -> CXChildVisitResult
|
internal typealias CursorVisitor = (cursor: CValue<CXCursor>, parent: CValue<CXCursor>) -> CXChildVisitResult
|
||||||
|
|
||||||
internal fun visitChildren(parent: CValue<CXCursor>, visitor: CursorVisitor) {
|
internal fun visitChildren(parent: CValue<CXCursor>, visitor: CursorVisitor) {
|
||||||
val visitorPtr = StableObjPtr.create(visitor)
|
val visitorStableRef = StableObjPtr.create(visitor)
|
||||||
try {
|
try {
|
||||||
val clientData = visitorPtr.value
|
val clientData = visitorStableRef.asCPointer()
|
||||||
clang_visitChildren(parent, staticCFunction { cursorIt, parentIt, clientDataIt ->
|
clang_visitChildren(parent, staticCFunction { cursorIt, parentIt, clientDataIt ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
val visitorIt = clientDataIt!!.asStableRef<CursorVisitor>().get()
|
||||||
val visitorIt = StableObjPtr.fromValue(clientDataIt!!).get() as CursorVisitor
|
|
||||||
visitorIt(cursorIt, parentIt)
|
visitorIt(cursorIt, parentIt)
|
||||||
}, clientData)
|
}, clientData)
|
||||||
} finally {
|
} finally {
|
||||||
visitorPtr.dispose()
|
visitorStableRef.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,19 +155,19 @@ internal fun visitChildren(translationUnit: CXTranslationUnit, visitor: CursorVi
|
|||||||
|
|
||||||
internal fun getFields(type: CValue<CXType>): List<CValue<CXCursor>> {
|
internal fun getFields(type: CValue<CXType>): List<CValue<CXCursor>> {
|
||||||
val result = mutableListOf<CValue<CXCursor>>()
|
val result = mutableListOf<CValue<CXCursor>>()
|
||||||
val resultPtr = StableObjPtr.create(result)
|
val resultStableRef = StableRef.create(result)
|
||||||
try {
|
try {
|
||||||
val clientData = resultPtr.value
|
val clientData = resultStableRef.asCPointer()
|
||||||
|
|
||||||
@Suppress("NAME_SHADOWING", "UNCHECKED_CAST")
|
@Suppress("NAME_SHADOWING")
|
||||||
clang_Type_visitFields(type, staticCFunction { cursor, clientData ->
|
clang_Type_visitFields(type, staticCFunction { cursor, clientData ->
|
||||||
val result = StableObjPtr.fromValue(clientData!!).get() as MutableList<CValue<CXCursor>>
|
val result = clientData!!.asStableRef<MutableList<CValue<CXCursor>>>().get()
|
||||||
result.add(cursor)
|
result.add(cursor)
|
||||||
CXVisitorResult.CXVisit_Continue
|
CXVisitorResult.CXVisit_Continue
|
||||||
}, clientData)
|
}, clientData)
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
resultPtr.dispose()
|
resultStableRef.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -340,16 +339,16 @@ internal interface Indexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslationUnit, options: Int, indexer: Indexer) {
|
internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslationUnit, options: Int, indexer: Indexer) {
|
||||||
val indexerStablePtr = StableObjPtr.create(indexer)
|
val indexerStableRef = StableObjPtr.create(indexer)
|
||||||
try {
|
try {
|
||||||
val clientData = indexerStablePtr.value
|
val clientData = indexerStableRef.asCPointer()
|
||||||
memScoped {
|
memScoped {
|
||||||
val indexerCallbacks = alloc<IndexerCallbacks>().apply {
|
val indexerCallbacks = alloc<IndexerCallbacks>().apply {
|
||||||
abortQuery = null
|
abortQuery = null
|
||||||
diagnostic = null
|
diagnostic = null
|
||||||
enteredMainFile = staticCFunction { clientData, mainFile, _ ->
|
enteredMainFile = staticCFunction { clientData, mainFile, _ ->
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val indexer = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
val indexer = clientData!!.asStableRef<Indexer>().get()
|
||||||
indexer.enteredMainFile(mainFile!!)
|
indexer.enteredMainFile(mainFile!!)
|
||||||
// We must ensure only interop types exist in function signature.
|
// We must ensure only interop types exist in function signature.
|
||||||
@Suppress("USELESS_CAST")
|
@Suppress("USELESS_CAST")
|
||||||
@@ -357,7 +356,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
|||||||
}
|
}
|
||||||
ppIncludedFile = staticCFunction { clientData, info ->
|
ppIncludedFile = staticCFunction { clientData, info ->
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val indexer = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
val indexer = clientData!!.asStableRef<Indexer>().get()
|
||||||
indexer.ppIncludedFile(info!!.pointed)
|
indexer.ppIncludedFile(info!!.pointed)
|
||||||
// We must ensure only interop types exist in function signature.
|
// We must ensure only interop types exist in function signature.
|
||||||
@Suppress("USELESS_CAST")
|
@Suppress("USELESS_CAST")
|
||||||
@@ -367,7 +366,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
|||||||
startedTranslationUnit = null
|
startedTranslationUnit = null
|
||||||
indexDeclaration = staticCFunction { clientData, info ->
|
indexDeclaration = staticCFunction { clientData, info ->
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val nativeIndex = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
val nativeIndex = clientData!!.asStableRef<Indexer>().get()
|
||||||
nativeIndex.indexDeclaration(info!!.pointed)
|
nativeIndex.indexDeclaration(info!!.pointed)
|
||||||
}
|
}
|
||||||
indexEntityReference = null
|
indexEntityReference = null
|
||||||
@@ -386,7 +385,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
indexerStablePtr.dispose()
|
indexerStableRef.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,48 +25,12 @@ import kotlin.reflect.full.declaredMemberProperties
|
|||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.jvm.reflect
|
import kotlin.reflect.jvm.reflect
|
||||||
|
|
||||||
/**
|
internal fun createStablePointer(any: Any): COpaquePointer = newGlobalRef(any).toCPointer()!!
|
||||||
* This class provides a way to create a stable handle to any Kotlin object.
|
|
||||||
* Its [value] can be safely passed to native code e.g. to be received in a Kotlin callback.
|
|
||||||
*
|
|
||||||
* Any [StableObjPtr] should be manually [disposed][dispose]
|
|
||||||
*/
|
|
||||||
data class StableObjPtr private constructor(val value: COpaquePointer) {
|
|
||||||
|
|
||||||
companion object {
|
internal fun disposeStablePointer(pointer: COpaquePointer) = deleteGlobalRef(pointer.toLong())
|
||||||
|
|
||||||
/**
|
@PublishedApi
|
||||||
* Creates a handle for given object.
|
internal fun derefStablePointer(pointer: COpaquePointer): Any = derefGlobalRef(pointer.toLong())
|
||||||
*/
|
|
||||||
fun create(any: Any) = fromValue(newGlobalRef(any))
|
|
||||||
|
|
||||||
private fun fromValue(value: NativePtr) = fromValue(interpretCPointer(value)!!)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates [StableObjPtr] from given raw value.
|
|
||||||
*
|
|
||||||
* @param value must be a [value] of some [StableObjPtr]
|
|
||||||
*/
|
|
||||||
fun fromValue(value: COpaquePointer) = StableObjPtr(value)
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadCallbacksLibrary()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes the handle. It must not be [used][get] after that.
|
|
||||||
*/
|
|
||||||
fun dispose() {
|
|
||||||
deleteGlobalRef(value.rawValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the object this handle was [created][create] for.
|
|
||||||
*/
|
|
||||||
fun get(): Any = derefGlobalRef(value.rawValue)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFieldCType(type: KType): CType<*> {
|
private fun getFieldCType(type: KType): CType<*> {
|
||||||
val classifier = type.classifier
|
val classifier = type.classifier
|
||||||
@@ -400,6 +364,8 @@ private fun loadCallbacksLibrary() {
|
|||||||
System.loadLibrary("callbacks")
|
System.loadLibrary("callbacks")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val topLevelInitializer = loadCallbacksLibrary()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to `ffi_type` struct instance.
|
* Reference to `ffi_type` struct instance.
|
||||||
|
|||||||
@@ -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>"))
|
||||||
|
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]
|
||||||
|
*/
|
||||||
|
data class StableRef<out T : Any> @PublishedApi internal constructor(
|
||||||
|
private val stablePtr: COpaquePointer,
|
||||||
|
private val ref: T // Note: storing the reference itself to avoid unchecked casts.
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a handle for given object.
|
||||||
|
*/
|
||||||
|
fun <T : Any> create(any: T) = StableRef<T>(createStablePointer(any), 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>()"))
|
||||||
|
fun fromValue(value: COpaquePointer) = value.asStableRef<Any>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use .asCPointer() instead", ReplaceWith("this.asCPointer()"))
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
fun get() = this.ref
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts to [StableRef] this opaque pointer produced by [StableRef.asCPointer].
|
||||||
|
*/
|
||||||
|
inline fun <reified T : Any> CPointer<*>.asStableRef() =
|
||||||
|
StableRef<T>(this, derefStablePointer(this) as T)
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package kotlinx.cinterop
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a way to create a stable handle to any Kotlin object.
|
|
||||||
* Its [value] can be safely passed to native code e.g. to be received in a Kotlin callback.
|
|
||||||
*
|
|
||||||
* Any [StableObjPtr] should be manually [disposed][dispose]
|
|
||||||
*/
|
|
||||||
data class StableObjPtr private constructor(val value: COpaquePointer) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a handle for given object.
|
|
||||||
*/
|
|
||||||
fun create(any: Any) = fromValue(createStablePointer(any))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates [StableObjPtr] from given raw value.
|
|
||||||
*
|
|
||||||
* @param value must be a [value] of some [StableObjPtr]
|
|
||||||
*/
|
|
||||||
fun fromValue(value: COpaquePointer) = StableObjPtr(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes the handle. It must not be [used][get] after that.
|
|
||||||
*/
|
|
||||||
fun dispose() {
|
|
||||||
disposeStablePointer(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the object this handle was [created][create] for.
|
|
||||||
*/
|
|
||||||
fun get(): Any = derefStablePointer(value)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SymbolName("Kotlin_Interop_createStablePointer")
|
|
||||||
private external fun createStablePointer(any: Any): COpaquePointer
|
|
||||||
|
|
||||||
@SymbolName("Kotlin_Interop_disposeStablePointer")
|
|
||||||
private external fun disposeStablePointer(pointer: COpaquePointer)
|
|
||||||
|
|
||||||
@SymbolName("Kotlin_Interop_derefStablePointer")
|
|
||||||
private external fun derefStablePointer(pointer: COpaquePointer): Any
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
@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
|
||||||
@@ -4,7 +4,7 @@ import kotlinx.cinterop.*
|
|||||||
import libcurl.*
|
import libcurl.*
|
||||||
|
|
||||||
class CUrl(val url: String) {
|
class CUrl(val url: String) {
|
||||||
val stablePtr = StableObjPtr.create(this)
|
val stableRef = StableRef.create(this)
|
||||||
|
|
||||||
val curl = curl_easy_init();
|
val curl = curl_easy_init();
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ class CUrl(val url: String) {
|
|||||||
curl_easy_setopt(curl, CURLOPT_URL, url)
|
curl_easy_setopt(curl, CURLOPT_URL, url)
|
||||||
val header = staticCFunction(::header_callback)
|
val header = staticCFunction(::header_callback)
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header)
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header)
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, stablePtr.value)
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, stableRef.asCPointer())
|
||||||
}
|
}
|
||||||
|
|
||||||
val header = Event<String>()
|
val header = Event<String>()
|
||||||
@@ -26,7 +26,7 @@ class CUrl(val url: String) {
|
|||||||
|
|
||||||
fun close() {
|
fun close() {
|
||||||
curl_easy_cleanup(curl)
|
curl_easy_cleanup(curl)
|
||||||
stablePtr.dispose()
|
stableRef.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ fun header_callback(buffer: CPointer<ByteVar>?, size: size_t, nitems: size_t, us
|
|||||||
if (buffer == null) return 0
|
if (buffer == null) return 0
|
||||||
val header = buffer.toKString((size * nitems).toInt()).trim()
|
val header = buffer.toKString((size * nitems).toInt()).trim()
|
||||||
if (userdata != null) {
|
if (userdata != null) {
|
||||||
val curl = StableObjPtr.fromValue(userdata).get() as CUrl
|
val curl = userdata.asStableRef<CUrl>().get()
|
||||||
curl.header(header)
|
curl.header(header)
|
||||||
}
|
}
|
||||||
return size * nitems
|
return size * nitems
|
||||||
@@ -49,7 +49,7 @@ fun header_callback(buffer: CPointer<ByteVar>?, size: size_t, nitems: size_t, us
|
|||||||
fun write_callback(buffer: COpaquePointer?, size: size_t, nitems: size_t, userdata: COpaquePointer?): size_t {
|
fun write_callback(buffer: COpaquePointer?, size: size_t, nitems: size_t, userdata: COpaquePointer?): size_t {
|
||||||
if (buffer == null) return 0
|
if (buffer == null) return 0
|
||||||
if (userdata != null) {
|
if (userdata != null) {
|
||||||
val curl = StableObjPtr.fromValue(userdata).get() as CUrl
|
val curl = userdata.asStableRef<CUrl>().get()
|
||||||
curl.data(buffer.)
|
curl.data(buffer.)
|
||||||
}
|
}
|
||||||
return size * nitems
|
return size * nitems
|
||||||
|
|||||||
Reference in New Issue
Block a user