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 fun visitChildren(parent: CValue<CXCursor>, visitor: CursorVisitor) {
|
||||
val visitorPtr = StableObjPtr.create(visitor)
|
||||
val visitorStableRef = StableObjPtr.create(visitor)
|
||||
try {
|
||||
val clientData = visitorPtr.value
|
||||
val clientData = visitorStableRef.asCPointer()
|
||||
clang_visitChildren(parent, staticCFunction { cursorIt, parentIt, clientDataIt ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val visitorIt = StableObjPtr.fromValue(clientDataIt!!).get() as CursorVisitor
|
||||
val visitorIt = clientDataIt!!.asStableRef<CursorVisitor>().get()
|
||||
visitorIt(cursorIt, parentIt)
|
||||
}, clientData)
|
||||
} 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>> {
|
||||
val result = mutableListOf<CValue<CXCursor>>()
|
||||
val resultPtr = StableObjPtr.create(result)
|
||||
val resultStableRef = StableRef.create(result)
|
||||
try {
|
||||
val clientData = resultPtr.value
|
||||
val clientData = resultStableRef.asCPointer()
|
||||
|
||||
@Suppress("NAME_SHADOWING", "UNCHECKED_CAST")
|
||||
@Suppress("NAME_SHADOWING")
|
||||
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)
|
||||
CXVisitorResult.CXVisit_Continue
|
||||
}, clientData)
|
||||
|
||||
} finally {
|
||||
resultPtr.dispose()
|
||||
resultStableRef.dispose()
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -340,16 +339,16 @@ internal interface Indexer {
|
||||
}
|
||||
|
||||
internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslationUnit, options: Int, indexer: Indexer) {
|
||||
val indexerStablePtr = StableObjPtr.create(indexer)
|
||||
val indexerStableRef = StableObjPtr.create(indexer)
|
||||
try {
|
||||
val clientData = indexerStablePtr.value
|
||||
val clientData = indexerStableRef.asCPointer()
|
||||
memScoped {
|
||||
val indexerCallbacks = alloc<IndexerCallbacks>().apply {
|
||||
abortQuery = null
|
||||
diagnostic = null
|
||||
enteredMainFile = staticCFunction { clientData, mainFile, _ ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val indexer = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
||||
val indexer = clientData!!.asStableRef<Indexer>().get()
|
||||
indexer.enteredMainFile(mainFile!!)
|
||||
// We must ensure only interop types exist in function signature.
|
||||
@Suppress("USELESS_CAST")
|
||||
@@ -357,7 +356,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
||||
}
|
||||
ppIncludedFile = staticCFunction { clientData, info ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val indexer = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
||||
val indexer = clientData!!.asStableRef<Indexer>().get()
|
||||
indexer.ppIncludedFile(info!!.pointed)
|
||||
// We must ensure only interop types exist in function signature.
|
||||
@Suppress("USELESS_CAST")
|
||||
@@ -367,7 +366,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
||||
startedTranslationUnit = null
|
||||
indexDeclaration = staticCFunction { clientData, info ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val nativeIndex = StableObjPtr.fromValue(clientData!!).get() as Indexer
|
||||
val nativeIndex = clientData!!.asStableRef<Indexer>().get()
|
||||
nativeIndex.indexDeclaration(info!!.pointed)
|
||||
}
|
||||
indexEntityReference = null
|
||||
@@ -386,7 +385,7 @@ internal fun indexTranslationUnit(index: CXIndex, translationUnit: CXTranslation
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
indexerStablePtr.dispose()
|
||||
indexerStableRef.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,48 +25,12 @@ import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.jvm.reflect
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
internal fun createStablePointer(any: Any): COpaquePointer = newGlobalRef(any).toCPointer()!!
|
||||
|
||||
companion object {
|
||||
internal fun disposeStablePointer(pointer: COpaquePointer) = deleteGlobalRef(pointer.toLong())
|
||||
|
||||
/**
|
||||
* Creates a handle for given object.
|
||||
*/
|
||||
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)
|
||||
|
||||
}
|
||||
@PublishedApi
|
||||
internal fun derefStablePointer(pointer: COpaquePointer): Any = derefGlobalRef(pointer.toLong())
|
||||
|
||||
private fun getFieldCType(type: KType): CType<*> {
|
||||
val classifier = type.classifier
|
||||
@@ -400,6 +364,8 @@ private fun loadCallbacksLibrary() {
|
||||
System.loadLibrary("callbacks")
|
||||
}
|
||||
|
||||
private val topLevelInitializer = loadCallbacksLibrary()
|
||||
|
||||
|
||||
/**
|
||||
* 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.*
|
||||
|
||||
class CUrl(val url: String) {
|
||||
val stablePtr = StableObjPtr.create(this)
|
||||
val stableRef = StableRef.create(this)
|
||||
|
||||
val curl = curl_easy_init();
|
||||
|
||||
@@ -12,7 +12,7 @@ class CUrl(val url: String) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url)
|
||||
val header = staticCFunction(::header_callback)
|
||||
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>()
|
||||
@@ -26,7 +26,7 @@ class CUrl(val url: String) {
|
||||
|
||||
fun close() {
|
||||
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
|
||||
val header = buffer.toKString((size * nitems).toInt()).trim()
|
||||
if (userdata != null) {
|
||||
val curl = StableObjPtr.fromValue(userdata).get() as CUrl
|
||||
val curl = userdata.asStableRef<CUrl>().get()
|
||||
curl.header(header)
|
||||
}
|
||||
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 {
|
||||
if (buffer == null) return 0
|
||||
if (userdata != null) {
|
||||
val curl = StableObjPtr.fromValue(userdata).get() as CUrl
|
||||
val curl = userdata.asStableRef<CUrl>().get()
|
||||
curl.data(buffer.)
|
||||
}
|
||||
return size * nitems
|
||||
|
||||
Reference in New Issue
Block a user