Lua Binding 的選擇
Rust 現在有數套 Lua binding,比較常被人提到的是 lua, hlua 與 rlua 。
lua 基本上是直接把 Lua 的 C API 直接移植,沒有做多餘的包裝。所以需要絕對的效能的話,這可能是你的最佳選擇。不過安全性跟 UB 就要自己處理了。
hlua 提供是比較高階的介面,不讓你直接存取 Lua Stack,可以視為 lua API 上的再一層包裝。彈性較低,可能不適合某些需求。
rlua 是由知名遊戲工作室 chucklefish 開發。延續 Rust 對安全性的要求,設計介面時也是以安全性為最高原則。在使用 rlua 的 API 時,不會產生任何 UB(由於 lua API 跟內部的運作方式,這種 API 真的很難做到…)也許犧牲了一點效能,不過對於 Rust 的使用者來說,這樣的 tradeoff 應該是蠻值得的。
最後我用的是 rlua。
老問題:Lifetime & ownership
剛開始用 rlua 的時候,很容易就撞到 lifetime 的問題。不過,就跟一般使用 Rust 一樣:如果遇到很難解的 lifetime 跟 ownership 問題,很可能架構設計上就錯了。
rlua 作者很詳盡的解釋了 rlua 許多的設計概念,也深入剖析了 Lua 本身設計帶來的影響。不過,這些解釋大多分散在各 github issue 之中。這邊稍微整理一下幾個重點:
- rlua 提供的所有的 reference type,像是
Function
、Table
這些指向 Lua 內部元素的參照,都不應該被另外存起來。 - rlua 提供的 reference type 也不應該被存到任何 Lua 內的
userdata
或是 Rust callback 之中。 - 傳進 rlua 中的任何值都必須是
Send
(因為 lua 本身是Send
)跟'static
(因為你沒辦法知道 Lua 何時會 GC 掉這些值,難以找出精確的 lifetime。) - 3 的限制讓傳值給 lua 變的複雜許多。rlua 提供了
scope
API,可以用一個暫時的 scope 將不符合條件的值傳給 lua。傳過去的資料在 scope 結束後就會被銷毀,避免複雜的 lifetime 問題。