Initial commit
This commit is contained in:
commit
7ae25ab368
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
*.generated.lua
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "luajit"]
|
||||||
|
path = luajit
|
||||||
|
url = https://luajit.org/git/luajit.git
|
5
.luarc.json
Normal file
5
.luarc.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||||
|
"runtime.version": "LuaJIT",
|
||||||
|
"diagnostics.disable": ["redefined-local"]
|
||||||
|
}
|
757
Cargo.lock
generated
Normal file
757
Cargo.lock
generated
Normal file
@ -0,0 +1,757 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbindgen"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "975982cdb7ad6a142be15bdf84aea7ec6a9e5d4d797c004d43185b24cfe4e684"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"heck",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"syn",
|
||||||
|
"tempfile",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_home"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.172"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libmimalloc-sys"
|
||||||
|
version = "0.1.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "luabi"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"bstr",
|
||||||
|
"cbindgen",
|
||||||
|
"cc",
|
||||||
|
"clap",
|
||||||
|
"digest",
|
||||||
|
"glob",
|
||||||
|
"libmimalloc-sys",
|
||||||
|
"lz4_flex",
|
||||||
|
"md-5",
|
||||||
|
"mimalloc",
|
||||||
|
"owo-colors",
|
||||||
|
"sha2",
|
||||||
|
"thiserror",
|
||||||
|
"which",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lz4_flex"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
|
||||||
|
dependencies = [
|
||||||
|
"twox-hash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md-5"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mimalloc"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af"
|
||||||
|
dependencies = [
|
||||||
|
"libmimalloc-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "4.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"getrandom",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_write",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_write"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "twox-hash"
|
||||||
|
version = "1.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.14.2+wasi-0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "which"
|
||||||
|
version = "7.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"env_home",
|
||||||
|
"rustix",
|
||||||
|
"winsafe",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winsafe"
|
||||||
|
version = "0.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.39.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["luabi"]
|
||||||
|
resolver = "3"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
lto = "fat"
|
||||||
|
strip = "debuginfo"
|
24
luabi/Cargo.toml
Normal file
24
luabi/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "luabi"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
blake2 = "0.10.6"
|
||||||
|
bstr = "1.12.0"
|
||||||
|
clap = { version = "4.5.39", features = ["derive"] }
|
||||||
|
digest = "0.10.7"
|
||||||
|
libmimalloc-sys = "0.1.42"
|
||||||
|
lz4_flex = "0.11.3"
|
||||||
|
md-5 = "0.10.6"
|
||||||
|
mimalloc = "0.1.46"
|
||||||
|
owo-colors = "4.2.1"
|
||||||
|
sha2 = "0.10.9"
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cbindgen = "0.29.0"
|
||||||
|
cc = "1.2.25"
|
||||||
|
glob = "0.3.2"
|
||||||
|
lz4_flex = "0.11.3"
|
||||||
|
which = "7.0.3"
|
189
luabi/build.rs
Normal file
189
luabi/build.rs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
use cbindgen::{EnumConfig, Language, Style};
|
||||||
|
use glob::glob;
|
||||||
|
use lz4_flex::compress_prepend_size;
|
||||||
|
use std::{
|
||||||
|
env::{var, var_os},
|
||||||
|
fs::{File, copy, create_dir_all, read_dir, write},
|
||||||
|
io::{self, Write},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::Command,
|
||||||
|
thread::available_parallelism,
|
||||||
|
};
|
||||||
|
use which::which;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let target = var("TARGET").unwrap();
|
||||||
|
let host = var("HOST").unwrap();
|
||||||
|
let src_path: PathBuf = var("CARGO_MANIFEST_DIR").unwrap().into();
|
||||||
|
let out_path: PathBuf = var("OUT_DIR").unwrap().into();
|
||||||
|
let luajit_path = out_path.join("luajit/src");
|
||||||
|
let lib_rt_path = out_path.join("runtime.lua.lz4");
|
||||||
|
|
||||||
|
copy_recursive(src_path.join("../luajit"), luajit_path.parent().unwrap())
|
||||||
|
.expect("failed to copy luajit source");
|
||||||
|
|
||||||
|
build_luajit(&target, &host, &luajit_path);
|
||||||
|
build_lua(&src_path, &lib_rt_path);
|
||||||
|
|
||||||
|
println!("cargo::rerun-if-changed={}/src", src_path.display());
|
||||||
|
println!("cargo::rustc-link-arg=-rdynamic");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_luajit(target: &str, host: &str, src_path: &Path) {
|
||||||
|
let mut make = match host {
|
||||||
|
"x86_64-unknown-dragonfly" => Command::new("gmake"),
|
||||||
|
"x86_64-unknown-freebsd" => Command::new("gmake"),
|
||||||
|
_ => Command::new("make"),
|
||||||
|
};
|
||||||
|
|
||||||
|
make.current_dir(&src_path)
|
||||||
|
.arg("-e")
|
||||||
|
.arg(format!(
|
||||||
|
"-j{}",
|
||||||
|
available_parallelism().map_or(1, |n| n.into())
|
||||||
|
))
|
||||||
|
.env("BUILDMODE", "static");
|
||||||
|
|
||||||
|
let mut xcflags = vec![
|
||||||
|
"-fPIC",
|
||||||
|
"-DLUAJIT_ENABLE_LUA52COMPAT", // enable lua 5.2 compatibility
|
||||||
|
"-DLUAJIT_USE_SYSMALLOC", // disable the built-in allocator (we provide our own)
|
||||||
|
];
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
xcflags.extend_from_slice(&[
|
||||||
|
"-DLUA_USE_ASSERT",
|
||||||
|
"-DLUA_USE_APICHECK",
|
||||||
|
"-DLUAJIT_USE_GDBJIT", // gdb support
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.ends_with("-apple-darwin") && var_os("MACOSX_DEPLOYMENT_TARGET").is_none() {
|
||||||
|
make.env(
|
||||||
|
"MACOSX_DEPLOYMENT_TARGET",
|
||||||
|
match target.split_once("-").unwrap() {
|
||||||
|
("aarch64", _) | ("arm64e", _) => "11.0",
|
||||||
|
("x86_64", _) | ("x86_64h", _) => "10.11",
|
||||||
|
(arch, _) => panic!("unknown macos target architecture '{arch}'"),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if target.contains("-windows-") || target.ends_with("-windows") {
|
||||||
|
make.env("TARGET_SYS", "Windows");
|
||||||
|
} else if target.contains("-linux-") || target.ends_with("-linux") {
|
||||||
|
make.env("TARGET_SYS", "Linux");
|
||||||
|
} else {
|
||||||
|
make.env("TARGET_SYS", "Other");
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_cc = cc::Build::new().target(host).get_compiler();
|
||||||
|
let host_cc_path = which(host_cc.path()).expect("failed to find host cc");
|
||||||
|
|
||||||
|
if var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" {
|
||||||
|
make.env("HOST_CC", format!("{} -m32", host_cc_path.display())); // cross-compile to 32-bit on 64-bit host
|
||||||
|
} else {
|
||||||
|
make.env("HOST_CC", &host_cc_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_cc = cc::Build::new().target(target).get_compiler();
|
||||||
|
let target_cc_path = which(target_cc.path()).expect("failed to find target cc");
|
||||||
|
let target_bin_path = target_cc_path.parent().unwrap();
|
||||||
|
|
||||||
|
if let Some(prefix) = target_cc_path.to_str().unwrap().strip_suffix("gcc") {
|
||||||
|
make.env("DEFAULT_CC", "gcc").env("CROSS", prefix);
|
||||||
|
} else if let Some(prefix) = target_cc_path.to_str().unwrap().strip_suffix("clang") {
|
||||||
|
make.env("DEFAULT_CC", "clang").env("CROSS", prefix);
|
||||||
|
} else {
|
||||||
|
make.env("DEFAULT_CC", target_cc_path.file_name().unwrap())
|
||||||
|
.env("CROSS", format!("{}/", target_bin_path.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
make.env("XCFLAGS", xcflags.join(" "));
|
||||||
|
println!("running luajit make: {make:?}");
|
||||||
|
|
||||||
|
let status = make.status().expect("failed to execute make");
|
||||||
|
if !status.success() {
|
||||||
|
panic!("failed to compile luajit: {status}: {make:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo::rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET");
|
||||||
|
println!("cargo::rustc-link-search=native={}", src_path.display());
|
||||||
|
println!("cargo::rustc-link-lib=static=luajit");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_lua(src_path: &Path, out_path: &Path) {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
writeln!(&mut buf, "require(\"ffi\").cdef [[").unwrap();
|
||||||
|
cbindgen::generate_with_config(
|
||||||
|
src_path,
|
||||||
|
cbindgen::Config {
|
||||||
|
language: Language::C,
|
||||||
|
no_includes: true,
|
||||||
|
documentation: false,
|
||||||
|
line_length: 1000,
|
||||||
|
style: Style::Type,
|
||||||
|
enumeration: EnumConfig {
|
||||||
|
prefix_with_name: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("failed to generate bindings")
|
||||||
|
.write(&mut buf);
|
||||||
|
writeln!(&mut buf, "]]").unwrap();
|
||||||
|
|
||||||
|
let mut paths = glob(&format!("{}/src/**/*.lua", src_path.display()))
|
||||||
|
.unwrap()
|
||||||
|
.collect::<Result<Vec<PathBuf>, _>>()
|
||||||
|
.unwrap();
|
||||||
|
paths.sort();
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
|
let name = path
|
||||||
|
.strip_prefix(src_path)
|
||||||
|
.unwrap()
|
||||||
|
.strip_prefix("src")
|
||||||
|
.unwrap()
|
||||||
|
.with_extension("")
|
||||||
|
.to_string_lossy()
|
||||||
|
.replace("/", ".");
|
||||||
|
|
||||||
|
writeln!(&mut buf, "package.preload[\"lb.{name}\"] = function(...)").unwrap();
|
||||||
|
std::io::copy(
|
||||||
|
&mut File::open(path).expect("failed to open file"),
|
||||||
|
&mut buf,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writeln!(&mut buf, "end").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// debugging:
|
||||||
|
write(
|
||||||
|
PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap()).join("runtime.generated.lua"),
|
||||||
|
&buf,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
write(out_path, compress_prepend_size(&buf)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_recursive(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
|
||||||
|
create_dir_all(&dst)?;
|
||||||
|
|
||||||
|
for entry in read_dir(src)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let ftype = entry.file_type()?;
|
||||||
|
if entry.file_name().to_str() == Some(".git") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = dst.as_ref().join(entry.file_name());
|
||||||
|
if ftype.is_dir() {
|
||||||
|
copy_recursive(entry.path(), path)?;
|
||||||
|
} else {
|
||||||
|
copy(entry.path(), path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
112
luabi/src/core.lua
Normal file
112
luabi/src/core.lua
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
|
||||||
|
local mm_names = {
|
||||||
|
-- known luajit metamethods (see lj_obj.h)
|
||||||
|
__index = true,
|
||||||
|
__newindex = true,
|
||||||
|
__gc = true,
|
||||||
|
__eq = true,
|
||||||
|
__len = true,
|
||||||
|
__lt = true,
|
||||||
|
__le = true,
|
||||||
|
__concat = true,
|
||||||
|
__call = true,
|
||||||
|
__add = true,
|
||||||
|
__sub = true,
|
||||||
|
__mul = true,
|
||||||
|
__div = true,
|
||||||
|
__mod = true,
|
||||||
|
__pow = true,
|
||||||
|
__unm = true,
|
||||||
|
__metatable = true,
|
||||||
|
__tostring = true,
|
||||||
|
__pairs = true,
|
||||||
|
__ipairs = true,
|
||||||
|
|
||||||
|
-- luabi metamethods
|
||||||
|
__init = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function Type(name, def)
|
||||||
|
local obj_mt = {
|
||||||
|
__tostring = function(self)
|
||||||
|
return string.format("%s %p", name, self)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local type = {}
|
||||||
|
local type_mt = {
|
||||||
|
__tostring = function(self)
|
||||||
|
return string.format("lb.core::Type<%s> %p", name, self)
|
||||||
|
end,
|
||||||
|
|
||||||
|
__call = function(_, ...)
|
||||||
|
local self = setmetatable({}, obj_mt)
|
||||||
|
local __init = obj_mt.__init
|
||||||
|
if __init ~= nil then __init(self, ...) end
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in pairs(def) do
|
||||||
|
if mm_names[key] == true then
|
||||||
|
obj_mt[key] = value
|
||||||
|
else
|
||||||
|
type[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
type_mt.__index = obj_mt.__index
|
||||||
|
obj_mt.__index = type
|
||||||
|
return setmetatable(type, type_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Module = Type("lb.core::Module", {
|
||||||
|
__init = function(self, name, def)
|
||||||
|
self.__name = name
|
||||||
|
for key, value in pairs(def) do
|
||||||
|
self[key] = value
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
__tostring = function(self)
|
||||||
|
return string.format("lb.core::Module<%s> %p", self.__name, self)
|
||||||
|
end,
|
||||||
|
|
||||||
|
__call = function(self, ...)
|
||||||
|
local call = self.__call
|
||||||
|
if call ~= nil then return call(...) end
|
||||||
|
local default = self.__default
|
||||||
|
if default ~= nil then return default end
|
||||||
|
error(string.format("module '%s' has no default export", self.__name))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
local function unwrap_opt(res)
|
||||||
|
-- read value out and forget option cdata
|
||||||
|
if res.has == true then return res.value end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unwrap_res(res)
|
||||||
|
if res.err ~= nil then
|
||||||
|
-- read message out, drop error cdata and throw
|
||||||
|
local buf = C.lb_error_msg(res.err)
|
||||||
|
local msg = ffi.string(buf.ptr, buf.len)
|
||||||
|
C.lb_error_drop(buf)
|
||||||
|
error(msg)
|
||||||
|
else
|
||||||
|
-- error is nil so value must have been initialised
|
||||||
|
-- read value out and forget result cdata
|
||||||
|
return res.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Module("lb.core", {
|
||||||
|
Module = Module,
|
||||||
|
Type = Type,
|
||||||
|
|
||||||
|
unwrap_opt = unwrap_opt,
|
||||||
|
unwrap_res = unwrap_res,
|
||||||
|
})
|
275
luabi/src/core.rs
Normal file
275
luabi/src/core.rs
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
use crate::{
|
||||||
|
hash::LbHashError,
|
||||||
|
str::{LbStr, LbStrError},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LbOpt<T> {
|
||||||
|
value: MaybeUninit<T>,
|
||||||
|
has: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LbOpt<T> {
|
||||||
|
pub fn some(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
value: MaybeUninit::new(value),
|
||||||
|
has: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Self {
|
||||||
|
value: MaybeUninit::uninit(),
|
||||||
|
has: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Option<T>> for LbOpt<T> {
|
||||||
|
fn from(value: Option<T>) -> Self {
|
||||||
|
match value {
|
||||||
|
Some(value) => Self::some(value),
|
||||||
|
None => Self::none(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for LbOpt<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.has {
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: since option has a value, value must have been initialised
|
||||||
|
self.value.assume_init_drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LbRes<T> {
|
||||||
|
value: MaybeUninit<T>,
|
||||||
|
err: Option<Box<LbError>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LbRes<T> {
|
||||||
|
pub fn ok(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
value: MaybeUninit::new(value),
|
||||||
|
err: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn err(error: LbError) -> Self {
|
||||||
|
Self {
|
||||||
|
value: MaybeUninit::uninit(),
|
||||||
|
err: Some(Box::new(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Result<T, LbError>> for LbRes<T> {
|
||||||
|
fn from(value: Result<T, LbError>) -> Self {
|
||||||
|
match value {
|
||||||
|
Ok(value) => Self::ok(value),
|
||||||
|
Err(error) => Self::err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for LbRes<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.err.is_none() {
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: since result is not an error, value must have been initialised
|
||||||
|
self.value.assume_init_drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LbError {
|
||||||
|
#[error("{0}")]
|
||||||
|
String(#[from] LbStrError),
|
||||||
|
#[error("{0}")]
|
||||||
|
Hash(#[from] LbHashError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LbError {
|
||||||
|
pub fn message(&self) -> String {
|
||||||
|
format!("{self}")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_error_drop(&mut self) {
|
||||||
|
unsafe { ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn lb_error_msg(&self) -> LbStr {
|
||||||
|
self.message().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LbVec<T> {
|
||||||
|
ptr: NonNull<T>,
|
||||||
|
len: usize,
|
||||||
|
cap: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LbVec<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Vec::new().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for LbVec<T> {
|
||||||
|
type Target = [T];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for LbVec<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Vec<T>> for LbVec<T> {
|
||||||
|
fn from(value: Vec<T>) -> Self {
|
||||||
|
let len = value.len();
|
||||||
|
let cap = value.capacity();
|
||||||
|
let ptr = ManuallyDrop::new(value).as_mut_ptr();
|
||||||
|
Self {
|
||||||
|
ptr: unsafe { NonNull::new_unchecked(ptr) }.into(),
|
||||||
|
len,
|
||||||
|
cap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<LbVec<T>> for Vec<T> {
|
||||||
|
fn from(value: LbVec<T>) -> Self {
|
||||||
|
let len = value.len;
|
||||||
|
let cap = value.cap;
|
||||||
|
let ptr = ManuallyDrop::new(value).ptr.as_ptr();
|
||||||
|
unsafe { Vec::from_raw_parts(ptr, len, cap) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LbMap<K, V> {
|
||||||
|
inner: Box<LbMapImpl<K, V>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct LbMapImpl<K, V>(HashMap<K, V>);
|
||||||
|
|
||||||
|
impl<K, V> LbMap<K, V> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Box::new(LbMapImpl(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Deref for LbMap<K, V> {
|
||||||
|
type Target = HashMap<K, V>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> DerefMut for LbMap<K, V> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.inner.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> From<HashMap<K, V>> for LbMap<K, V> {
|
||||||
|
fn from(value: HashMap<K, V>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Box::new(LbMapImpl(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> From<LbMap<K, V>> for HashMap<K, V> {
|
||||||
|
fn from(value: LbMap<K, V>) -> Self {
|
||||||
|
value.inner.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type LbBuf = LbVec<u8>;
|
||||||
|
|
||||||
|
impl LbBuf {
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_buf_new(ptr: *const u8, len: usize) -> LbBuf {
|
||||||
|
unsafe { slice::from_raw_parts(ptr, len).to_vec().into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_buf_drop(&mut self) {
|
||||||
|
unsafe { ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type LbParams = LbMap<String, String>;
|
||||||
|
|
||||||
|
impl LbParams {
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn lb_params_new() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_params_drop(&mut self) {
|
||||||
|
unsafe { ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_params_get(&self, key: *const u8, key_len: usize) -> LbOpt<LbStr> {
|
||||||
|
std::str::from_utf8(unsafe { slice::from_raw_parts(key, key_len) })
|
||||||
|
.ok()
|
||||||
|
.and_then(|key| self.get(key).map(|s| s.to_owned().into()))
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_params_set(
|
||||||
|
&mut self,
|
||||||
|
key: *const u8,
|
||||||
|
key_len: usize,
|
||||||
|
value: *const u8,
|
||||||
|
value_len: usize,
|
||||||
|
) -> LbRes<bool> {
|
||||||
|
std::str::from_utf8(unsafe { slice::from_raw_parts(key, key_len) })
|
||||||
|
.and_then(|key| {
|
||||||
|
std::str::from_utf8(unsafe { slice::from_raw_parts(value, value_len) })
|
||||||
|
.map(|value| (key, value))
|
||||||
|
})
|
||||||
|
.map_err(|err| LbStrError::InvalidUtf8(err).into())
|
||||||
|
.map(|(key, value)| self.insert(key.into(), value.into()))
|
||||||
|
.map(|_| true)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_params_del(&mut self, key: *const u8, key_len: usize) -> bool {
|
||||||
|
std::str::from_utf8(unsafe { slice::from_raw_parts(key, key_len) })
|
||||||
|
.map(|key| self.remove(key).is_some())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
14
luabi/src/fs.rs
Normal file
14
luabi/src/fs.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// use std::{
|
||||||
|
// ffi::{CStr, OsStr, OsString, c_char, c_int},
|
||||||
|
// slice,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// #[unsafe(no_mangle)]
|
||||||
|
// pub unsafe extern "C" fn lb_fs_touch(path: *const u8, path_len: usize) -> c_int {
|
||||||
|
// let path = match std::str::from_utf8(unsafe { slice::from_raw_parts(path, path_len) }) {
|
||||||
|
// Ok(path) => path,
|
||||||
|
// Err(_) => return -1, // invalid utf8 string
|
||||||
|
// };
|
||||||
|
|
||||||
|
// 0
|
||||||
|
// }
|
56
luabi/src/hash.lua
Normal file
56
luabi/src/hash.lua
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
local core = require("lb.core")
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
|
||||||
|
local algs = {
|
||||||
|
md5 = C.LbHasherAlgorithm_Md5,
|
||||||
|
sha224 = C.LbHasherAlgorithm_Sha224,
|
||||||
|
sha256 = C.LbHasherAlgorithm_Sha256,
|
||||||
|
sha384 = C.LbHasherAlgorithm_Sha384,
|
||||||
|
sha512 = C.LbHasherAlgorithm_Sha512,
|
||||||
|
blake2b = C.LbHasherAlgorithm_Blake2b,
|
||||||
|
blake2s = C.LbHasherAlgorithm_Blake2s,
|
||||||
|
}
|
||||||
|
|
||||||
|
local alg_names = {}
|
||||||
|
for name, _ in pairs(algs) do
|
||||||
|
alg_names[#alg_names + 1] = name
|
||||||
|
end
|
||||||
|
table.sort(alg_names)
|
||||||
|
|
||||||
|
local Hasher = core.Type("lb.hash::Hasher", {
|
||||||
|
__init = function(self, name, params)
|
||||||
|
if name == nil then
|
||||||
|
error("algorithm must be specified: one of " .. table.concat(alg_names, ", "))
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = tostring(name)
|
||||||
|
local alg = algs[name]
|
||||||
|
if alg == nil then error(string.format("unknown hash algorithm '%s'", name)) end
|
||||||
|
|
||||||
|
self.__name = name
|
||||||
|
self.__ptr = ffi.gc(core.unwrap_res(C.lb_hasher_new(alg, nil)), C.lb_hasher_drop)
|
||||||
|
end,
|
||||||
|
|
||||||
|
name = function(self)
|
||||||
|
return self.__name
|
||||||
|
end,
|
||||||
|
|
||||||
|
update = function(self, data)
|
||||||
|
local data = tostring(data)
|
||||||
|
C.lb_hasher_update(self.__ptr, data, data:len())
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
|
||||||
|
done = function(self, format)
|
||||||
|
local buf = C.lb_hasher_digest(self.__ptr)
|
||||||
|
local digest = ffi.string(buf.ptr, buf.len)
|
||||||
|
C.lb_buf_drop(buf)
|
||||||
|
return digest
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
return core.Module("lb.hash", {
|
||||||
|
__call = Hasher,
|
||||||
|
Hasher = Hasher,
|
||||||
|
})
|
157
luabi/src/hash.rs
Normal file
157
luabi/src/hash.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use crate::core::{LbBuf, LbError, LbParams, LbRes};
|
||||||
|
use blake2::{Blake2b512, Blake2bVar, Blake2s256, Blake2sVar};
|
||||||
|
use digest::InvalidOutputSize;
|
||||||
|
use md5::Md5;
|
||||||
|
use sha2::{Sha224, Sha256, Sha384, Sha512, Sha512_224, Sha512_256};
|
||||||
|
use std::{mem, num::ParseIntError, ptr, slice};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LbHashError {
|
||||||
|
#[error("invalid parameter '{0}': {1}")]
|
||||||
|
InvalidIntParam(&'static str, ParseIntError),
|
||||||
|
#[error("invalid parameter '{PARAM_OUTPUT_SIZE}': {0}")]
|
||||||
|
InvalidOutputSize(#[from] InvalidOutputSize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LbHasher {
|
||||||
|
alg: LbHasherAlgorithm,
|
||||||
|
hasher: Box<LbHasherImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum LbHasherAlgorithm {
|
||||||
|
Md5,
|
||||||
|
Sha224,
|
||||||
|
Sha256,
|
||||||
|
Sha384,
|
||||||
|
Sha512,
|
||||||
|
Blake2b,
|
||||||
|
Blake2s,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum LbHasherImpl {
|
||||||
|
Md5(Md5),
|
||||||
|
Sha224(Sha224),
|
||||||
|
Sha256(Sha256),
|
||||||
|
Sha384(Sha384),
|
||||||
|
Sha512(Sha512),
|
||||||
|
Sha512_224(Sha512_224),
|
||||||
|
Sha512_256(Sha512_256),
|
||||||
|
Blake2b(Blake2bVar),
|
||||||
|
Blake2b512(Blake2b512),
|
||||||
|
Blake2s(Blake2sVar),
|
||||||
|
Blake2s256(Blake2s256),
|
||||||
|
}
|
||||||
|
|
||||||
|
const PARAM_OUTPUT_SIZE: &'static str = "output_size";
|
||||||
|
|
||||||
|
fn param_output_size(params: Option<&LbParams>) -> Result<Option<usize>, LbHashError> {
|
||||||
|
params
|
||||||
|
.and_then(|p| p.get(PARAM_OUTPUT_SIZE))
|
||||||
|
.map(|s| s.parse())
|
||||||
|
.transpose()
|
||||||
|
.map_err(|err| LbHashError::InvalidIntParam(PARAM_OUTPUT_SIZE, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LbHasher {
|
||||||
|
pub fn new(alg: LbHasherAlgorithm, params: Option<&LbParams>) -> Result<Self, LbHashError> {
|
||||||
|
use digest::{Digest, VariableOutput};
|
||||||
|
let hasher = Box::new(match alg {
|
||||||
|
LbHasherAlgorithm::Md5 => LbHasherImpl::Md5(Digest::new()),
|
||||||
|
LbHasherAlgorithm::Sha224 => LbHasherImpl::Sha224(Digest::new()),
|
||||||
|
LbHasherAlgorithm::Sha256 => LbHasherImpl::Sha256(Digest::new()),
|
||||||
|
LbHasherAlgorithm::Sha384 => LbHasherImpl::Sha384(Digest::new()),
|
||||||
|
LbHasherAlgorithm::Sha512 => param_output_size(params).and_then(|size| match size {
|
||||||
|
Some(224) => Ok(LbHasherImpl::Sha512_224(Digest::new())),
|
||||||
|
Some(256) => Ok(LbHasherImpl::Sha512_256(Digest::new())),
|
||||||
|
Some(512) | None => Ok(LbHasherImpl::Sha512(Digest::new())),
|
||||||
|
_ => Err(LbHashError::InvalidOutputSize(InvalidOutputSize)),
|
||||||
|
})?,
|
||||||
|
LbHasherAlgorithm::Blake2b => {
|
||||||
|
param_output_size(params).and_then(|size| match size {
|
||||||
|
Some(512) | None => Ok(LbHasherImpl::Blake2b512(Blake2b512::new())),
|
||||||
|
size => VariableOutput::new(size.unwrap())
|
||||||
|
.map(LbHasherImpl::Blake2b)
|
||||||
|
.map_err(LbHashError::InvalidOutputSize),
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
LbHasherAlgorithm::Blake2s => {
|
||||||
|
param_output_size(params).and_then(|size| match size {
|
||||||
|
Some(256) | None => Ok(LbHasherImpl::Blake2s256(Blake2s256::new())),
|
||||||
|
size => VariableOutput::new(size.unwrap())
|
||||||
|
.map(LbHasherImpl::Blake2s)
|
||||||
|
.map_err(LbHashError::InvalidOutputSize),
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self { alg, hasher })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, data: impl AsRef<[u8]>) {
|
||||||
|
use digest::Update;
|
||||||
|
match *self.hasher {
|
||||||
|
LbHasherImpl::Md5(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha224(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha256(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha384(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha512(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha512_224(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Sha512_256(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Blake2b(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Blake2b512(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Blake2s(ref mut s) => s.update(data.as_ref()),
|
||||||
|
LbHasherImpl::Blake2s256(ref mut s) => s.update(data.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn digest(&mut self) -> Vec<u8> {
|
||||||
|
use digest::{DynDigest, VariableOutput};
|
||||||
|
match *self.hasher {
|
||||||
|
LbHasherImpl::Md5(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha224(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha256(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha384(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha512(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha512_224(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Sha512_256(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Blake2b(ref mut s) => {
|
||||||
|
mem::replace(s, Blake2bVar::new(s.output_size()).unwrap()).finalize_boxed()
|
||||||
|
}
|
||||||
|
LbHasherImpl::Blake2b512(ref mut s) => s.finalize_reset(),
|
||||||
|
LbHasherImpl::Blake2s(ref mut s) => {
|
||||||
|
mem::replace(s, Blake2sVar::new(s.output_size()).unwrap()).finalize_boxed()
|
||||||
|
}
|
||||||
|
LbHasherImpl::Blake2s256(ref mut s) => s.finalize_reset(),
|
||||||
|
}
|
||||||
|
.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn lb_hasher_new(
|
||||||
|
alg: LbHasherAlgorithm,
|
||||||
|
params: Option<&LbParams>,
|
||||||
|
) -> LbRes<Self> {
|
||||||
|
Self::new(alg, params).map_err(LbError::Hash).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_hasher_drop(&mut self) {
|
||||||
|
unsafe { ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_hasher_update(&mut self, data: *const u8, data_len: usize) {
|
||||||
|
self.update(unsafe { slice::from_raw_parts(data, data_len) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn lb_hasher_digest(&mut self) -> LbBuf {
|
||||||
|
self.digest().into()
|
||||||
|
}
|
||||||
|
}
|
4
luabi/src/lib.rs
Normal file
4
luabi/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod core;
|
||||||
|
pub mod fs;
|
||||||
|
pub mod hash;
|
||||||
|
pub mod str;
|
924
luabi/src/lua.rs
Normal file
924
luabi/src/lua.rs
Normal file
@ -0,0 +1,924 @@
|
|||||||
|
#![allow(non_camel_case_types, non_snake_case, unused)]
|
||||||
|
use bstr::{BStr, BString, ByteSlice};
|
||||||
|
use libmimalloc_sys::{mi_free, mi_realloc};
|
||||||
|
use std::{
|
||||||
|
backtrace::Backtrace,
|
||||||
|
ffi::{CStr, CString, NulError},
|
||||||
|
fmt::{self, Display},
|
||||||
|
marker::{PhantomData, PhantomPinned},
|
||||||
|
os::raw::{c_char, c_double, c_int, c_void},
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
rc::Rc,
|
||||||
|
slice,
|
||||||
|
thread::{self, Thread},
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/***** lua.h *****/
|
||||||
|
/* mark for precompiled code (`<esc>Lua') */
|
||||||
|
pub const LUA_SIGNATURE: &[u8] = b"\x1bLJ";
|
||||||
|
|
||||||
|
/* option for multiple returns in `lua_pcall' and `lua_call' */
|
||||||
|
pub const LUA_MULTRET: c_int = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** pseudo-indices
|
||||||
|
*/
|
||||||
|
pub const LUA_REGISTRYINDEX: c_int = -10000;
|
||||||
|
pub const LUA_ENVIRONINDEX: c_int = -10001;
|
||||||
|
pub const LUA_GLOBALSINDEX: c_int = -10002;
|
||||||
|
|
||||||
|
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||||
|
LUA_GLOBALSINDEX - i
|
||||||
|
}
|
||||||
|
|
||||||
|
/* thread status */
|
||||||
|
pub const LUA_OK: c_int = 0;
|
||||||
|
pub const LUA_YIELD: c_int = 1;
|
||||||
|
pub const LUA_ERRRUN: c_int = 2;
|
||||||
|
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||||
|
pub const LUA_ERRMEM: c_int = 4;
|
||||||
|
pub const LUA_ERRERR: c_int = 5;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct lua_State {
|
||||||
|
_data: [u8; 0],
|
||||||
|
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** functions that read/write blocks when loading/dumping Lua chunks
|
||||||
|
*/
|
||||||
|
pub type lua_Reader = unsafe extern "C-unwind" fn(
|
||||||
|
L: *mut lua_State,
|
||||||
|
ud: *mut c_void,
|
||||||
|
sz: *mut usize,
|
||||||
|
) -> *const c_char;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** prototype for memory-allocation functions
|
||||||
|
*/
|
||||||
|
pub type lua_Writer = unsafe extern "C-unwind" fn(
|
||||||
|
L: *mut lua_State,
|
||||||
|
p: *const c_void,
|
||||||
|
sz: usize,
|
||||||
|
ud: *mut c_void,
|
||||||
|
) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** prototype for memory-allocation functions
|
||||||
|
*/
|
||||||
|
pub type lua_Alloc = unsafe extern "C" fn(
|
||||||
|
ud: *mut c_void,
|
||||||
|
ptr: *mut c_void,
|
||||||
|
osize: usize,
|
||||||
|
nsize: usize,
|
||||||
|
) -> *mut c_void;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** basic types
|
||||||
|
*/
|
||||||
|
pub const LUA_TNONE: c_int = -1;
|
||||||
|
pub const LUA_TNIL: c_int = 0;
|
||||||
|
pub const LUA_TBOOLEAN: c_int = 1;
|
||||||
|
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||||
|
pub const LUA_TNUMBER: c_int = 3;
|
||||||
|
pub const LUA_TSTRING: c_int = 4;
|
||||||
|
pub const LUA_TTABLE: c_int = 5;
|
||||||
|
pub const LUA_TFUNCTION: c_int = 6;
|
||||||
|
pub const LUA_TUSERDATA: c_int = 7;
|
||||||
|
pub const LUA_TTHREAD: c_int = 8;
|
||||||
|
pub const LUA_TCDATA: c_int = 10;
|
||||||
|
|
||||||
|
/* minimum Lua stack available to a C function */
|
||||||
|
pub const LUA_MINSTACK: c_int = 20;
|
||||||
|
|
||||||
|
/* type of numbers in Lua */
|
||||||
|
pub type lua_Number = c_double;
|
||||||
|
|
||||||
|
/* type for integer functions */
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
pub type lua_Integer = i32;
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
pub type lua_Integer = i64;
|
||||||
|
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
/*
|
||||||
|
** state manipulation
|
||||||
|
*/
|
||||||
|
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
||||||
|
pub fn lua_close(L: *mut lua_State);
|
||||||
|
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||||
|
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** basic stack manipulation
|
||||||
|
*/
|
||||||
|
pub fn lua_gettop(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn lua_settop(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_remove(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
||||||
|
pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||||
|
|
||||||
|
pub fn lua_isnumber(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_isstring(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_isuserdata(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_type(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||||
|
|
||||||
|
pub fn lua_equal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||||
|
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||||
|
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||||
|
|
||||||
|
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
|
||||||
|
pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||||
|
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||||
|
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||||
|
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||||
|
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||||
|
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||||
|
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** push functions (C -> stack)
|
||||||
|
*/
|
||||||
|
pub fn lua_pushnil(L: *mut lua_State);
|
||||||
|
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
||||||
|
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
||||||
|
pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize);
|
||||||
|
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char);
|
||||||
|
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||||
|
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||||
|
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||||
|
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||||
|
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** get functions (Lua -> stack)
|
||||||
|
*/
|
||||||
|
pub fn lua_gettable(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||||
|
pub fn lua_rawget(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: c_int);
|
||||||
|
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||||
|
pub fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void;
|
||||||
|
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||||
|
pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** set functions (stack -> Lua)
|
||||||
|
*/
|
||||||
|
pub fn lua_settable(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||||
|
pub fn lua_rawset(L: *mut lua_State, idx: c_int);
|
||||||
|
pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: c_int);
|
||||||
|
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||||
|
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** `load' and `call' functions (load and run Lua code)
|
||||||
|
*/
|
||||||
|
pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int);
|
||||||
|
pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int;
|
||||||
|
pub fn lua_cpcall(L: *mut lua_State, func: lua_CFunction, ud: *mut c_void) -> c_int;
|
||||||
|
pub fn lua_load(
|
||||||
|
L: *mut lua_State,
|
||||||
|
reader: lua_Reader,
|
||||||
|
dt: *mut c_void,
|
||||||
|
chunkname: *const c_char,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn lua_dump(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** coroutine functions
|
||||||
|
*/
|
||||||
|
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
|
||||||
|
pub fn lua_resume(L: *mut lua_State, narg: c_int) -> c_int;
|
||||||
|
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** garbage-collection function and options
|
||||||
|
*/
|
||||||
|
pub const LUA_GCSTOP: c_int = 0;
|
||||||
|
pub const LUA_GCRESTART: c_int = 1;
|
||||||
|
pub const LUA_GCCOLLECT: c_int = 2;
|
||||||
|
pub const LUA_GCCOUNT: c_int = 3;
|
||||||
|
pub const LUA_GCCOUNTB: c_int = 4;
|
||||||
|
pub const LUA_GCSTEP: c_int = 5;
|
||||||
|
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||||
|
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||||
|
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** miscellaneous functions
|
||||||
|
*/
|
||||||
|
pub fn lua_error(L: *mut lua_State) -> !;
|
||||||
|
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
|
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
||||||
|
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
|
||||||
|
pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** ===============================================================
|
||||||
|
** some useful macros
|
||||||
|
** ===============================================================
|
||||||
|
*/
|
||||||
|
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||||
|
unsafe { lua_settop(L, -n - 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||||
|
unsafe { lua_createtable(L, 0, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||||
|
unsafe { (lua_pushcfunction(L, f), lua_setglobal(L, n)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||||
|
unsafe { lua_pushcclosure(L, f, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_strlen(L: *mut lua_State, i: c_int) -> usize {
|
||||||
|
unsafe { lua_objlen(L, i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TFUNCTION) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TTABLE) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TNIL) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TBOOLEAN) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TTHREAD) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) == LUA_TNONE) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
|
unsafe { (lua_type(L, n) <= LUA_TNIL) as c_int }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: impl AsRef<[u8]>) {
|
||||||
|
unsafe { luab_pushstring(L, s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_setglobal(L: *mut lua_State, s: *const c_char) {
|
||||||
|
unsafe { lua_setfield(L, LUA_GLOBALSINDEX, s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_getglobal(L: *mut lua_State, s: *const c_char) {
|
||||||
|
unsafe { lua_getfield(L, LUA_GLOBALSINDEX, s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||||
|
unsafe { lua_tolstring(L, i, ptr::null_mut()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** compatibility macros and functions
|
||||||
|
*/
|
||||||
|
pub unsafe fn lua_getregistry(L: *mut lua_State) {
|
||||||
|
unsafe { lua_pushvalue(L, LUA_REGISTRYINDEX) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lua_getgccount(L: *mut lua_State) -> c_int {
|
||||||
|
unsafe { lua_gc(L, LUA_GCCOUNT, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type lua_Chunkreader = lua_Reader;
|
||||||
|
pub type lua_Chunkwriter = lua_Writer;
|
||||||
|
|
||||||
|
/* hack */
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn lua_setlevel(from: *mut lua_State, to: *mut lua_State);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================================
|
||||||
|
** Debug API
|
||||||
|
** =======================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Event codes
|
||||||
|
*/
|
||||||
|
pub const LUA_HOOKCALL: c_int = 0;
|
||||||
|
pub const LUA_HOOKRET: c_int = 1;
|
||||||
|
pub const LUA_HOOKLINE: c_int = 2;
|
||||||
|
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||||
|
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Event masks
|
||||||
|
*/
|
||||||
|
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||||
|
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||||
|
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||||
|
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||||
|
|
||||||
|
/* Functions to be called by the debuger in specific events */
|
||||||
|
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||||
|
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||||
|
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||||
|
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||||
|
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||||
|
pub fn lua_getupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
||||||
|
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
||||||
|
pub fn lua_sethook(
|
||||||
|
L: *mut lua_State,
|
||||||
|
func: Option<lua_Hook>,
|
||||||
|
mask: c_int,
|
||||||
|
count: c_int,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||||
|
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From Lua 5.2. */
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn lua_upvalueid(L: *mut lua_State, idx: c_int, n: c_int) -> *mut c_void;
|
||||||
|
pub fn lua_upvaluejoin(L: *mut lua_State, idx1: c_int, n1: c_int, idx2: c_int, n2: c_int);
|
||||||
|
pub fn lua_loadx(
|
||||||
|
L: *mut lua_State,
|
||||||
|
reader: lua_Reader,
|
||||||
|
dt: *mut c_void,
|
||||||
|
chunkname: *const c_char,
|
||||||
|
mode: *const c_char,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
||||||
|
pub fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int);
|
||||||
|
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||||
|
pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From Lua 5.3. */
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* activation record */
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct lua_Debug {
|
||||||
|
pub event: c_int,
|
||||||
|
pub name: *const c_char, /* (n) */
|
||||||
|
pub namewhat: *const c_char, /* (n) `global', `local', `field', `method' */
|
||||||
|
pub what: *const c_char, /* (S) `Lua', `C', `main', `tail' */
|
||||||
|
pub source: *const c_char, /* (S) */
|
||||||
|
pub currentline: c_int, /* (l) */
|
||||||
|
pub nups: c_int, /* (u) number of upvalues */
|
||||||
|
pub linedefined: c_int, /* (S) */
|
||||||
|
pub lastlinedefined: c_int, /* (S) */
|
||||||
|
pub short_src: [c_char; LUA_IDSIZE as usize], /* (S) */
|
||||||
|
/* private part */
|
||||||
|
i_ci: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const LUA_IDSIZE: c_int = 60; /* Size of lua_Debug.short_src. */
|
||||||
|
|
||||||
|
/***** lualib.h *****/
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_io(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_os(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_bit(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_jit(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_ffi(L: *mut lua_State) -> c_int;
|
||||||
|
pub fn luaopen_string_buffer(L: *mut lua_State) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** lauxlib.h *****/
|
||||||
|
#[link(name = "luajit", kind = "static")]
|
||||||
|
unsafe extern "C-unwind" {
|
||||||
|
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Library {
|
||||||
|
Base,
|
||||||
|
Math,
|
||||||
|
String,
|
||||||
|
Table,
|
||||||
|
Io,
|
||||||
|
Os,
|
||||||
|
Package,
|
||||||
|
Debug,
|
||||||
|
Bit,
|
||||||
|
Jit,
|
||||||
|
Ffi,
|
||||||
|
StringBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Library {
|
||||||
|
pub const ALL: &[Library] = &[
|
||||||
|
Library::Base,
|
||||||
|
Library::Math,
|
||||||
|
Library::String,
|
||||||
|
Library::Table,
|
||||||
|
Library::Io,
|
||||||
|
Library::Os,
|
||||||
|
Library::Package,
|
||||||
|
Library::Debug,
|
||||||
|
Library::Bit,
|
||||||
|
Library::Jit,
|
||||||
|
Library::Ffi,
|
||||||
|
Library::StringBuffer,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Base => "base",
|
||||||
|
Self::Math => "math",
|
||||||
|
Self::String => "string",
|
||||||
|
Self::Table => "table",
|
||||||
|
Self::Io => "io",
|
||||||
|
Self::Os => "os",
|
||||||
|
Self::Package => "package",
|
||||||
|
Self::Debug => "debug",
|
||||||
|
Self::Bit => "bit",
|
||||||
|
Self::Jit => "jit",
|
||||||
|
Self::Ffi => "ffi",
|
||||||
|
Self::StringBuffer => "string_buffer",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_open_fn(&self) -> lua_CFunction {
|
||||||
|
match self {
|
||||||
|
Self::Base => luaopen_base,
|
||||||
|
Self::Math => luaopen_math,
|
||||||
|
Self::String => luaopen_string,
|
||||||
|
Self::Table => luaopen_table,
|
||||||
|
Self::Io => luaopen_io,
|
||||||
|
Self::Os => luaopen_os,
|
||||||
|
Self::Package => luaopen_package,
|
||||||
|
Self::Debug => luaopen_debug,
|
||||||
|
Self::Bit => luaopen_bit,
|
||||||
|
Self::Jit => luaopen_jit,
|
||||||
|
Self::Ffi => luaopen_ffi,
|
||||||
|
Self::StringBuffer => luaopen_string_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("out of memory")]
|
||||||
|
OutOfMemory,
|
||||||
|
#[error("syntax error in chunk '{chunk}': {msg}")]
|
||||||
|
Syntax { chunk: BString, msg: BString },
|
||||||
|
#[error("bad chunkname: {0}")]
|
||||||
|
BadChunkName(NulError),
|
||||||
|
#[error("{msg}")]
|
||||||
|
Call { msg: BString },
|
||||||
|
#[error("{msg}")]
|
||||||
|
Resume { msg: BString, trace: BString },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub enum LoadMode {
|
||||||
|
#[default]
|
||||||
|
Auto,
|
||||||
|
Text,
|
||||||
|
Binary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadMode {
|
||||||
|
fn mode_str(&self) -> &'static CStr {
|
||||||
|
match self {
|
||||||
|
Self::Auto => c"bt",
|
||||||
|
Self::Text => c"t",
|
||||||
|
Self::Binary => c"b",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub enum ResumeStatus {
|
||||||
|
#[default]
|
||||||
|
Ok,
|
||||||
|
Suspended,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn luab_pushstring(L: *mut lua_State, s: impl AsRef<[u8]>) {
|
||||||
|
unsafe { lua_pushlstring(L, s.as_ref().as_ptr().cast(), s.as_ref().len()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: returned reference is valid only as long as it is present in the stack
|
||||||
|
unsafe fn luab_tostring(L: *mut lua_State, idx: c_int) -> Option<&'static BStr> {
|
||||||
|
unsafe {
|
||||||
|
let mut len = 0;
|
||||||
|
let ptr = lua_tolstring(L, idx, &mut len);
|
||||||
|
(!ptr.is_null()).then(|| slice::from_raw_parts(ptr.cast(), len).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn luab_load(
|
||||||
|
L: *mut lua_State,
|
||||||
|
name: Option<&CStr>,
|
||||||
|
chunk: impl AsRef<[u8]>,
|
||||||
|
mode: LoadMode,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
type ReaderState<'s> = Option<&'s [u8]>;
|
||||||
|
let name = name.unwrap_or(c"?");
|
||||||
|
let mut state: ReaderState = Some(chunk.as_ref());
|
||||||
|
|
||||||
|
unsafe extern "C-unwind" fn read_cb(
|
||||||
|
L: *mut lua_State,
|
||||||
|
state: *mut c_void,
|
||||||
|
size: *mut usize,
|
||||||
|
) -> *const c_char {
|
||||||
|
unsafe {
|
||||||
|
if let Some(chunk) = (*(state as *mut ReaderState)).take() {
|
||||||
|
*size = chunk.len();
|
||||||
|
chunk.as_ptr() as *const c_char
|
||||||
|
} else {
|
||||||
|
*size = 0;
|
||||||
|
ptr::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_checkstack(L, 1);
|
||||||
|
|
||||||
|
match lua_loadx(
|
||||||
|
L,
|
||||||
|
read_cb,
|
||||||
|
&raw mut state as *mut c_void,
|
||||||
|
name.as_ptr(),
|
||||||
|
mode.mode_str().as_ptr(),
|
||||||
|
) {
|
||||||
|
LUA_OK => Ok(()),
|
||||||
|
LUA_ERRMEM => {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
Err(Error::OutOfMemory)
|
||||||
|
}
|
||||||
|
LUA_ERRSYNTAX => {
|
||||||
|
let chunk = name.to_bytes().as_bstr().to_owned();
|
||||||
|
let msg = luab_tostring(L, -1)
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.unwrap_or(b"unknown error".into())
|
||||||
|
.to_owned();
|
||||||
|
lua_pop(L, 1);
|
||||||
|
Err(Error::Syntax { chunk, msg })
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn luab_call(L: *mut lua_State, narg: c_int, nret: c_int) -> Result<c_int, Error> {
|
||||||
|
unsafe {
|
||||||
|
assert!(
|
||||||
|
matches!(lua_status(L), LUA_OK | LUA_ERRERR), // see lua_pcall in lj_api.c
|
||||||
|
"thread {L:?} called in wrong state"
|
||||||
|
);
|
||||||
|
|
||||||
|
let base = lua_gettop(L) - (narg + 1);
|
||||||
|
match lua_pcall(L, narg, nret, 0) {
|
||||||
|
LUA_OK => {
|
||||||
|
let n = lua_gettop(L) - base;
|
||||||
|
assert!(n == nret || nret == LUA_MULTRET);
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
LUA_ERRMEM => {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
Err(Error::OutOfMemory)
|
||||||
|
}
|
||||||
|
LUA_ERRRUN | LUA_ERRERR => {
|
||||||
|
let msg = luab_tostring(L, -1)
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.unwrap_or(b"unknown error".into())
|
||||||
|
.to_owned();
|
||||||
|
lua_pop(L, 1);
|
||||||
|
Err(Error::Call { msg })
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn luab_resume(L: *mut lua_State, narg: c_int) -> Result<ResumeStatus, Error> {
|
||||||
|
unsafe {
|
||||||
|
assert!(
|
||||||
|
matches!(lua_status(L), LUA_OK | LUA_YIELD), // see lua_resume in lj_api.c
|
||||||
|
"cannot resume dead thread {L:?}"
|
||||||
|
);
|
||||||
|
|
||||||
|
match lua_resume(L, narg) {
|
||||||
|
LUA_OK => Ok(ResumeStatus::Ok),
|
||||||
|
LUA_YIELD => Ok(ResumeStatus::Suspended),
|
||||||
|
LUA_ERRMEM => {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
Err(Error::OutOfMemory)
|
||||||
|
}
|
||||||
|
LUA_ERRRUN | LUA_ERRERR => {
|
||||||
|
luaL_traceback(L, L, ptr::null(), 0);
|
||||||
|
|
||||||
|
let msg = luab_tostring(L, -2)
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.unwrap_or(b"unknown error".into())
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let trace = luab_tostring(L, -1)
|
||||||
|
.map(|s| s.strip_prefix(b"stack traceback:\n").unwrap_or(s).as_bstr())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.unwrap_or(b"<stack trace unavailable>".into())
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
lua_pop(L, 2);
|
||||||
|
Err(Error::Resume { msg, trace })
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct StateInner(NonNull<lua_State>);
|
||||||
|
|
||||||
|
impl Drop for StateInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { lua_close(self.0.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct State {
|
||||||
|
inner: Rc<StateInner>,
|
||||||
|
ptr: NonNull<lua_State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new() -> Result<Self, Error> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = NonNull::new(lua_newstate(Self::alloc_cb, ptr::null_mut()))
|
||||||
|
.ok_or(Error::OutOfMemory)?;
|
||||||
|
|
||||||
|
let state = Self {
|
||||||
|
inner: Rc::new(StateInner(ptr)),
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
lua_atpanic(state.as_ptr(), Self::panic_cb);
|
||||||
|
|
||||||
|
// lua_pushcfunction(state.as_ptr(), lua_handle_panic);
|
||||||
|
// lua_replace(state.as_ptr(), lua_upvalueindex(1));
|
||||||
|
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn alloc_cb(
|
||||||
|
_ud: *mut c_void,
|
||||||
|
ptr: *mut c_void,
|
||||||
|
_osize: usize,
|
||||||
|
nsize: usize,
|
||||||
|
) -> *mut c_void {
|
||||||
|
unsafe {
|
||||||
|
// NOTE: same as the reference implementation used by luaL_newstate
|
||||||
|
// https://www.lua.org/manual/5.1/manual.html#lua_Alloc
|
||||||
|
if nsize == 0 {
|
||||||
|
mi_free(ptr);
|
||||||
|
ptr::null_mut()
|
||||||
|
} else {
|
||||||
|
mi_realloc(ptr, nsize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C-unwind" fn panic_cb(L: *mut lua_State) -> c_int {
|
||||||
|
unsafe {
|
||||||
|
let msg = luab_tostring(L, -1)
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.unwrap_or(b"unknown error".into());
|
||||||
|
|
||||||
|
panic!("{msg}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_lib(&self, lib: Library) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 2);
|
||||||
|
lua_pushcfunction(self.as_ptr(), lib.get_open_fn());
|
||||||
|
lua_pushliteral(self.as_ptr(), lib.name());
|
||||||
|
luab_call(self.as_ptr(), 1, 0).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_libs<'a>(&self, libs: impl IntoIterator<Item = &'a Library>) -> Result<(), Error> {
|
||||||
|
for lib in libs {
|
||||||
|
self.open_lib(*lib)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *mut lua_State {
|
||||||
|
self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top(&self) -> c_int {
|
||||||
|
unsafe { lua_gettop(self.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absindex(&self, idx: c_int) -> c_int {
|
||||||
|
// SAFETY: refer to index2adr in lj_api.c
|
||||||
|
unsafe {
|
||||||
|
if idx > 0 {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
assert!(idx <= top, "invalid stack index {idx} (size={top})");
|
||||||
|
idx
|
||||||
|
} else if idx > LUA_REGISTRYINDEX {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
let i = top + idx + 1;
|
||||||
|
assert!(0 < i && i <= top, "invalid stack index {idx} (size={top})");
|
||||||
|
i
|
||||||
|
} else {
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&self, idx: c_int) {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 1);
|
||||||
|
lua_pushvalue(self.as_ptr(), self.absindex(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_string(&self, s: impl AsRef<[u8]>) {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 1);
|
||||||
|
luab_pushstring(self.as_ptr(), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_pointer<T>(&self, p: *const T) {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 1);
|
||||||
|
lua_pushlightuserdata(self.as_ptr(), p as *mut c_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_require(&self, module: impl AsRef<[u8]>) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 2);
|
||||||
|
luab_pushstring(self.as_ptr(), "require");
|
||||||
|
lua_rawget(self.as_ptr(), LUA_GLOBALSINDEX);
|
||||||
|
luab_pushstring(self.as_ptr(), module);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self, idx: c_int) -> Option<BString> {
|
||||||
|
// SAFETY: we copy the lua-owned string immediately so no reference to it is kept
|
||||||
|
unsafe { luab_tostring(self.as_ptr(), self.absindex(idx)).map(|s| s.to_owned()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&self, n: c_int) {
|
||||||
|
unsafe {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
assert!(
|
||||||
|
0 < n && n <= top,
|
||||||
|
"cannot pop {n} value(s) from the stack (size={top})"
|
||||||
|
);
|
||||||
|
lua_pop(self.as_ptr(), n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_table(&self, idx: c_int) {
|
||||||
|
unsafe {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
assert!(top >= 1, "expected 1 value on the stack (size={top})");
|
||||||
|
lua_rawget(self.as_ptr(), self.absindex(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_table(&self, idx: c_int) {
|
||||||
|
unsafe {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
assert!(top >= 2, "expected 2 values on the stack (size={top})");
|
||||||
|
lua_rawset(self.as_ptr(), self.absindex(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(
|
||||||
|
&self,
|
||||||
|
name: Option<impl AsRef<[u8]>>,
|
||||||
|
chunk: impl AsRef<[u8]>,
|
||||||
|
mode: LoadMode,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
luab_load(
|
||||||
|
self.as_ptr(),
|
||||||
|
name.map(|s| CString::new(s.as_ref()))
|
||||||
|
.transpose()
|
||||||
|
.map_err(Error::BadChunkName)?
|
||||||
|
.as_deref(),
|
||||||
|
chunk,
|
||||||
|
mode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, narg: c_int, nret: c_int) -> Result<c_int, Error> {
|
||||||
|
unsafe {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
let need = narg + 1; // need function on the stack too
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
0 <= need && need <= top,
|
||||||
|
"expected {need} value(s) on the stack (size={top})"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(0 <= nret || nret == LUA_MULTRET);
|
||||||
|
luab_call(self.as_ptr(), narg, nret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_thread(&self) -> State {
|
||||||
|
unsafe {
|
||||||
|
lua_checkstack(self.as_ptr(), 2);
|
||||||
|
|
||||||
|
// SAFETY: lua_newthread never returns null, but may throw on oom
|
||||||
|
let state = State {
|
||||||
|
ptr: NonNull::new_unchecked(lua_newthread(self.as_ptr())),
|
||||||
|
inner: Rc::clone(&self.inner),
|
||||||
|
};
|
||||||
|
|
||||||
|
lua_pushlightuserdata(self.as_ptr(), state.as_ptr() as *mut c_void);
|
||||||
|
lua_insert(self.as_ptr(), -2); // map thread pointer to thread
|
||||||
|
lua_rawset(self.as_ptr(), LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resume(&self, narg: c_int) -> Result<ResumeStatus, Error> {
|
||||||
|
unsafe {
|
||||||
|
let top = lua_gettop(self.as_ptr());
|
||||||
|
let need = if lua_status(self.as_ptr()) == LUA_OK {
|
||||||
|
narg + 1 // need function on the stack too if not already suspended
|
||||||
|
} else {
|
||||||
|
narg
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
0 <= need && need <= top,
|
||||||
|
"expected {need} value(s) on the stack (size={top})"
|
||||||
|
);
|
||||||
|
|
||||||
|
luab_resume(self.as_ptr(), narg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for State {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let version = unsafe { *lua_version(self.as_ptr()) };
|
||||||
|
write!(f, "lua {version} {:p}", self.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
100
luabi/src/main.rs
Normal file
100
luabi/src/main.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use lz4_flex::decompress_size_prepended;
|
||||||
|
use mimalloc::MiMalloc;
|
||||||
|
use owo_colors::OwoColorize;
|
||||||
|
use std::{
|
||||||
|
backtrace::Backtrace,
|
||||||
|
fmt, fs, panic,
|
||||||
|
thread::{self, Thread},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod core;
|
||||||
|
pub mod hash;
|
||||||
|
pub mod lua;
|
||||||
|
pub mod str;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: MiMalloc = MiMalloc;
|
||||||
|
static LIB_RT: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/runtime.lua.lz4"));
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Path to the main script.
|
||||||
|
#[clap(value_name = "SCRIPT")]
|
||||||
|
path: Option<String>,
|
||||||
|
|
||||||
|
/// Execute string 'chunk'.
|
||||||
|
#[clap(long, short = 'e', value_name = "CHUNK")]
|
||||||
|
evals: Vec<String>,
|
||||||
|
|
||||||
|
/// Require library 'name'.
|
||||||
|
#[clap(long, short = 'l', value_name = "NAME")]
|
||||||
|
libs: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn panic_cb(panic: &panic::PanicHookInfo) {
|
||||||
|
struct Message<'a> {
|
||||||
|
thread: Thread,
|
||||||
|
panic: &'a panic::PanicHookInfo<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> fmt::Display for Message<'s> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let thread = self.thread.name().unwrap_or("<unnamed>");
|
||||||
|
let location = self.panic.location().unwrap();
|
||||||
|
let payload = self.panic.payload();
|
||||||
|
let msg = if let Some(s) = payload.downcast_ref::<&'static str>() {
|
||||||
|
s
|
||||||
|
} else if let Some(s) = payload.downcast_ref::<String>() {
|
||||||
|
s.as_str()
|
||||||
|
} else {
|
||||||
|
"unknown error"
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "thread '{thread}' panicked at {location}:\n{msg}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let trace = Backtrace::force_capture();
|
||||||
|
let thread = thread::current();
|
||||||
|
print!("{}\n{trace}", Message { thread, panic }.red());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
panic::set_hook(Box::new(panic_cb));
|
||||||
|
|
||||||
|
let args = Args::parse();
|
||||||
|
let vm = new_vm().unwrap_or_else(|err| panic!("failed to initialise runtime: {err}"));
|
||||||
|
let main = vm.new_thread();
|
||||||
|
|
||||||
|
if let Some(ref path) = args.path {
|
||||||
|
match main
|
||||||
|
.load(
|
||||||
|
Some(format!("@{path}")),
|
||||||
|
fs::read(path).unwrap_or_else(|err| panic!("{err}")),
|
||||||
|
lua::LoadMode::Auto,
|
||||||
|
)
|
||||||
|
.and_then(|()| main.resume(0))
|
||||||
|
{
|
||||||
|
Ok(status) => println!("ok: {status:?}"),
|
||||||
|
Err(err) => match err {
|
||||||
|
lua::Error::Resume { msg, trace } => println!("{}\n{trace}", msg.red()),
|
||||||
|
err => println!("{}", err.red()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_vm() -> Result<lua::State, lua::Error> {
|
||||||
|
let vm = lua::State::new()?;
|
||||||
|
vm.open_libs(lua::Library::ALL)?;
|
||||||
|
|
||||||
|
vm.load(
|
||||||
|
Some("@[luabi]"),
|
||||||
|
decompress_size_prepended(LIB_RT).unwrap(),
|
||||||
|
lua::LoadMode::Text,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
vm.call(0, 0)?;
|
||||||
|
Ok(vm)
|
||||||
|
}
|
70
luabi/src/str.rs
Normal file
70
luabi/src/str.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use crate::core::{LbBuf, LbRes};
|
||||||
|
use std::{
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
ptr, slice,
|
||||||
|
str::Utf8Error,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LbStrError {
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidUtf8(Utf8Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LbStr {
|
||||||
|
buf: LbBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LbStr {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
String::new().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for LbStr {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { std::str::from_utf8_unchecked(&self.buf) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for LbStr {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { std::str::from_utf8_unchecked_mut(&mut self.buf) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for LbStr {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self {
|
||||||
|
buf: value.into_bytes().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LbStr> for String {
|
||||||
|
fn from(value: LbStr) -> Self {
|
||||||
|
unsafe { String::from_utf8_unchecked(value.buf.into()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LbStr {
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_str_new(ptr: *const u8, len: usize) -> LbRes<LbStr> {
|
||||||
|
std::str::from_utf8(unsafe { slice::from_raw_parts(ptr, len) })
|
||||||
|
.map_err(|err| LbStrError::InvalidUtf8(err).into())
|
||||||
|
.map(|str| LbStr {
|
||||||
|
buf: str.as_bytes().to_vec().into(),
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lb_str_drop(&mut self) {
|
||||||
|
unsafe { ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
}
|
1
luajit
Submodule
1
luajit
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit f9140a622a0c44a99efb391cc1c2358bc8098ab7
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@ -0,0 +1 @@
|
|||||||
|
max_width = 100
|
7
stylua.toml
Normal file
7
stylua.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
syntax = "LuaJIT"
|
||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 2
|
||||||
|
column_width = 100
|
||||||
|
quote_style = "ForceDouble"
|
||||||
|
call_parentheses = "NoSingleTable"
|
||||||
|
collapse_simple_statement = "ConditionalOnly"
|
Loading…
x
Reference in New Issue
Block a user