I am working on an OSS library to wrap the LMDB ke...
# kotlin-native
k
I am working on an OSS library to wrap the LMDB key/value store in a KMP project. I am working on the native side for one of the functions that allows you to open a database and change the method for which values are compared. I want to expose this capability in a more Kotlin friendly way using something like Comparator<T> and then do the translation of Pointer to the API’s data type. Otherwise if not, the end-user will be forced to do this for each variation of platforms targeted. Here is the example that doesn’t work due to the staticCFunction capturing the closure of the comparator parameter passed to the function.
kotlinx.cinterop.staticCFunction must take an unbound, non-capturing function or lambda, but captures at
Copy code
actual fun dbiOpen(name: String?, comparator: Comparator<Val>, vararg options: DbiOption) : Dbi {
        val db = Dbi(name, this, *options)
        check(mdb_set_compare(ptr, db.dbi, staticCFunction { left, right ->
            comparator.compare(Val.forCompare(left!!.pointed), Val.forCompare(right!!.pointed))
        }))
        return db
    }
Project is located here: https://github.com/CoreyKaylor/kotlin-lmdb Any help would be appreciated if there is another creative way to provide this minor abstraction for the end-user.
I’m assuming for the lack of any guidance on this that there isn’t a clear way to accomplish this OOTB with KN. Is that fair to say?
l
Hi! 🙂 I am in the same boat as you! I am writing a KMP library to wrap Google's Leveldb. I had a similar issue where I needed to iterate on all keys in the database using the native iterator and I was wondering how to do so. I was sure I wanted a sequence, but I quickly realized that Kotlin sequences do not offer a safe cleanup callback to be executed once the sequence is closed. Indeed this issue exists for the stdlib API
File.useLines
:
Copy code
public inline fun <T> File.useLines(charset: Charset = Charsets.UTF_8, block: (Sequence<String>) -> T): T =
    bufferedReader(charset).use { block(it.lineSequence()) }
The problem here is that the stream has to be closed once finished using the sequence. Same gos for my case and I assume for yours too. Have a look at my implementation! I will probably help
Or if you need to "contain" the actions of the user because in the end you need to cleanup, you might want to have a look at NativeLevelDB#withSnapshot
k
In my case this is a function callback that the internal native API allows to expose the ability to compare two keys, hence my reason for wanting to use Comparator<Val>. I’m not actually iterating the sequence, the native lib is doing that internally in its own efficient ways, but calling this function so you can control the sort order of the keys. I’m sure I’ll take some time to look through your lib to see what kind of inspiration I can gain. I also maintain a similar library for the dotnet ecosystem with LMDB, so the lib itself is very familiar to me.
So if I want to allow this feature to exist in my lib for the end-user, it’s looking like I will have to expose the native internals to the end-user to allow this capability on the native-side of the KMP project, which is not ideal IMO.