Description
Problem
most apps/games have the concept of a main-thread, where a lu it will often hold onto thread-local objects (which must be created and destroyed on main-thread) like opengl buffers/textures or skia-like library objects or UI objects like widgets/windows/event loop.
At the same time, off-thread lua scripts are often Send
and can be used in async contexts (eg: loading assets from filesystem).
The current mlua
feature send
makes you choose one or the other. If you enable send
, you can't use it for main-thread. If you don't enable send
, you can't use it for async off-thread work.
Solution
It doesn't have to be done this way, but there's an obvious solution.
Just make Lua
(and all associated objects like UserData) generic over MSend
and only implement Lua: Send
if MSend: Send
.
// unit implements send. and most UserData would probably be send, so it's a good default.
struct Lua<T = ()> {
..,
_data: std::marker::PhantomData<T>
}
pub type LuaUnSend = Lua<*const ()>;
pub type UserDataUnSend = UserData<*const ()>;
// thread-unsafe objects will only impl UserDataUnSend
impl UserDataUnSend for OpenGLTexture { }
// thread-safe objects will remain generic, as they can work in same thread or cross thread cases.
impl<T> UserData<T> for MyNormalObject {}
It will add some complexity, but, now, users can create thread-unsafe lua instances on main-thread (or render thread or whatever), as well as thread-safe lua instances for off-thread/async work.
WorkArounds
Just accept the unsoundness, and impl Send for thread-unsafe objects. Just pray that you don't accidentally send/share the main-thread lua instance with off-threads.