Skip to content

only52607/luakt

Repository files navigation

LuaKt

Based on luaj, with enhanced interoperability with kotlin.

Get Started

Assuming you are already familiar with the basic API of luaj.

  1. Add the JitPack repository to your build file
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
  1. Add dependency with luaj
dependencies {
    implementation 'com.github.only52607.luakt:luakt:$luakt_version'
}

or without luaj

dependencies {
    implementation 'com.github.only52607.luakt:luakt-core:$luakt_version'
    implementation 'com.github.only52607.luakt:luakt-extension:$luakt_version'
}

luakt contains the following three modules
luakt-core: The core module of luakt, including features such as type coercion.
luakt-extension: The extension module of luakt provides some useful utility functions.
luakt-luaj: The luaj library, if your project already includes this library, you don’t need to add it repeatedly.

Example

main.kt

val globals = JsePlatform.standardGlobals()
globals.load(LuaKotlinLib())
globals.loadfile("main.lua").invoke()

main.lua

-- launch a thread
Thread = luakotlin.bindClass("java.lang.Thread")
Thread(function()
    print("print from new thread: " .. tostring(Thread:currentThread()))
end):start()

LuaKotlinLib

If you are going to interact with kotlin in luaj, you can use Luajava library, but LuaKotlin library is a better choice, it provides similar api to Luajava library, but it interacts with kotlin much simpler.

Examples

  • bind class
Thread = luakotlin.bindClass("java.lang.Thread")
  • new instance
-- bindClass and new
Random = luakotlin.bindClass("java.util.Random")
local r = luakotlin.new(Random, 10) -- use 10 as rand seed

-- newInstance
local r = luakotlin.newInstance("java.util.Random", 10)

-- with invoke sugar
Random = luakotlin.bindClass("java.util.Random")
local r = Random(10)
  • create proxy
Thread = luakotlin.bindClass("java.lang.Thread")
local runnable = luakotlin.createProxy("java.lang.Runnable", {
    run = function ()
        print("print from new thread: " .. tostring(Thread:currentThread()))
    end
})
Thread(runnable):start()

If a variable is a previously bound interface class, it can be called directly, which will return a proxy.

Thread = luakotlin.bindClass("java.lang.Thread")
Runnable = luakotlin.bindClass("java.lang.Runnable")
local runnable = Runnable {
    run = function ()
        print("print from new thread: " .. tostring(Thread:currentThread()))
    end
}
Thread(runnable):start()
  • Single abstract method(SAM) interface coercion

If the interface is a SAM interface, then the proxy can be created like below without specifying the method name.

Thread = luakotlin.bindClass("java.lang.Thread")
Runnable = luakotlin.bindClass("java.lang.Runnable")
-- use function to create proxy ofsingle method interface
local runnable = Runnable(function ()
    print("print from new thread: " .. tostring(Thread:currentThread()))
end)
Thread(runnable):start()

If the type of a parameter is a SAM interface, you can pass in a Lua function as follows, and the proxy will be created automatically.

Thread = luakotlin.bindClass("java.lang.Thread")
Thread(function ()
    print("print from new thread: " .. tostring(Thread:currentThread()))
end):start()
  • getter and setter
class Cat {
    var color: String = "white"
        set(value) {
            field = value
            println("color changed to $value")
        }
}
Cat = luakotlin.bindClass("Cat")
local c = Cat()
print(c.color) -- white
c.color = "pink" -- print "color changed to pink"
print(c.colot) -- pink
  • call suspend function blocking
class Cat {
    suspend fun sleep(duration: Long) {
        println("start sleep")
        delay(duration)
        println("wake up")
    }
}
Cat = luakotlin.bindClass("Cat")
local c = Cat()
c.sleep(1000) -- will block here
  • Interact with singleton objects
object TomCat {
    fun run() {
        prinln("TomCat is runnning")
    }
}
TomCat = luakotlin.bindClass("TomCat")
TomCat:run()
  • Interact with companion object
class Cat private constructor(val name: String) {
    companion object {
        fun create(name: String) {
            println("Cat $name is created")
            return Cat(name)
        }
    }
}
Cat = luakotlin.bindClass("Cat")
Cat:create("tom")

LuaKotlinExLib

LuaKotlinExlib provides more utility functions based on the LuaKotlinLib.

Load lib

globals.load(LuaKotlinlib()) // Make sure the LuaKotlinlib is preloaded
globals.load(LuaKotlinExlib())

Examples

  • import class
import "java.util.Random" -- Shorthand for `Random = luakotlin.bindClass("java.util.Random")`
Random(10).nextInt()

-- with alias
import("java.util.Random", MyRandom) -- Equivalent to `MyRandom = luakotlin.bindClass("java.util.Random")`
MyRandom(10).nextInt()
  • convert kotlin Collection or Map as lua table

The Array will be automatically converted to a lua table, but the Collection interface and Map interface will not be automatically converted. If you want to convert, you can use the totable function, which receives a userdata that implements the Collection or Map interface. And return the corresponding table.

object C {
    fun getMap(): Map<String, String> = mapOf(Pair("k1", "v1"))
    fun getList(): List<String> = listOf("v1", "v2")
}
local map = C:getMap()
for k, v in pairs(totable(map)) do
    print(k, v) -- k1 v1
end
local map = C:getList()
for i, v in ipairs(totable(map)) do
    print(i, v)
    -- v1
    -- v2
end 
  • convert lua table as kotlin Collection or Map
tolist({"v1", "v2"}) -- listOf("v1", "v2")
toset({"v1", "v2"}) -- setOf("v1", "v2")
tomap({ k1 = "v1", k2 = "v2" }) -- mapOf(Pair("k1", "v1"), Pair("k2", "v2"))

Extension functions

luakt also provides some useful extension functions in kotlin

Examples

  • create LuaFunction
val add = VarArgFunction { varargs ->
    return LuaValue.valueOf(varargs.checkint(1) + varargs.checkint(2))
}
  • deconstruct varargs
val v = LuaValue.varargsOf(LuaValue.valueOf(1), LuaValue.valueOf(2))
val (a, b) = v // deconstruct
print(a, b) // 1 2

License

MIT License