Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility for owned functions/values/etc to hold a Weak<LuaInner> instead of an Arc<LuaInner>? #367

Open
jcm2606 opened this issue Feb 12, 2024 · 2 comments

Comments

@jcm2606
Copy link

jcm2606 commented Feb 12, 2024

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.

@khvzak
Copy link
Member

khvzak commented Feb 12, 2024

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)

@jcm2606
Copy link
Author

jcm2606 commented Feb 13, 2024

Yep, this is actually close to what I had in mind for how owned objects holding Weaks 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants