mlua
mlua copied to clipboard
Possibility for owned functions/values/etc to hold a `Weak<LuaInner>` instead of an `Arc<LuaInner>`?
I was wondering if there's any possibility for an alternative form of owned functions/values/etc that internally hold a Weak<LuaInner>
instead of an Arc<LuaInner>
to mitigate any possible reference cycles when passing said owned function/value/etc back into Lua. I'm currently working on a Rust project that uses Lua as a scripting language and intend on capturing a Lua function and storing it in a Rust struct as an owned function to act as a callback, but I would then like to pass that Rust struct back into Lua which, as outlined in Mlua's docs, can very easily cause a reference cycle. Currently I'm working around this by maintaining a hashmap that maps numerical IDs to owned functions which lets me instead pass the ID into Lua, and this does work but it comes with a significant caveat that I need to provide access to this hashmap wherever I may want to call the owned function. I am aware that using a Weak
could be problematic in situations where you don't know for sure that Lua hasn't been dropped so I'm definitely not looking for the current implementation to switch to a Weak
, rather I'd like this to be a possibly unsafe alternative for when you know for sure that Lua is still alive and hasn't been dropped yet.
I don't like strong pointer in owned types either. As you correctly noted, switching Arc
to Weak
would lead to unsoundness when Lua is dropped while we still have a valid reference attached to owned object.
Alternatively (what's on my mind now), owned types can keep a Weak
reference but would require "upgrade" through an additional "proxy" type to temporary hold Arc
.
An example:
let lua = Lua::new();
let owned_table: OwnedTable = lua.globals().into_owned();
let table = owned_table.upgrade(); // a "proxy" object with strong reference to Lua
let print: Function = table.get("print")?;
It's not very ergonomic and has some limitations but should work.
Also, owned types can be implemented manually in user apps in a form like:
struct OwnedTable(Weak<Lua>, RegistryKey);
let lua = Arc::new(Lua::new());
let registry_key = lua.create_registry_value(lua.globals())?;
let owned_table = OwnedTable(Arc::downgrage(&lua), registry_key);
// to get access
let lua2 = owned_table.0.upgrade().unwrap();
let table: Table = lua2.registry_value(&owned_table.1)?;
it could be a good alternative to hashmaps (your current approach)
Yep, this is actually close to what I had in mind for how owned objects holding Weak
s would work. In my case I can guarantee that Lua isn't dropped while there's still weak references held in owned objects, as Lua lives throughout the entire duration of my program while all owned objects are created and dropped before the program ends, but for other cases where there isn't that guarantee this seems decent for making sure that you're aware of the risks.