Lifetimes of a callback given to a Rust library from Lua

Hi all,

I'm trying to put together a Lua library using mlua - and I've got the basics going -
But now I'm trying to let Lua set a callback on a userdata object.

I'm using add_field_method_set to handle the setting of the "EventHandler" field on the userdata - but I get a "cannot infer lifetimes" error - and I'm still struggling a bit to get my head around the lifetime concept (but working on it!)

If Lua is creating a function, I'm not clear what the lifetime of the corresponding mlua::LuaFunction is, or how to establish the appropriate lifetime, or indeed how to reason about the relative lifetimes of things sent to / returned from Lua.

If anyone can offer any insight or clarification, it'd be much appreciated! Meantime I'll keep chipping away at it.

cannot infer an appropriate lifetime for lifetime parameter `'lua` due to conflicting requirements

note: ...so that the types are compatible
note: expected `mlua::FromLua<'b>`
         found `mlua::FromLua<'_>`
note: but, the lifetime must be valid for the static lifetime...
note: expected `std::option::Option<mlua::Function<'static>>`
         found `std::option::Option<mlua::Function<'_>>`rustc(E0495)
use mlua::prelude::*;

struct CallbackHolder<'a> {
    event_handler: Option<LuaFunction<'a>>,
}

impl LuaUserData for CallbackHolder<'static> {
    fn add_fields<'b, F: mlua::UserDataFields<'b, Self>>(fields: &mut F) {
        fields.add_field_method_set("EventHandler", |_, this, val| {
            this.event_handler = val;
            Ok(())
        })
    }
}

#[mlua::lua_module]
fn framework(lua: &Lua) -> LuaResult<LuaTable> {
    let globals = lua.globals();
    // globals.set("sum", lua.create_function(sum)?)?;
    // globals.set("sumcb", lua.create_function(sum_callback)?)?;
    globals.set("holder", lua.create_userdata(CallbackHolder { event_handler: None })?)?;
    Ok(lua.create_table()?)
}

You just have to look at the signature of Lua::create_function(), nothing else:

pub fn create_function<'lua, 'callback, A, R, F>(
    &'lua self,
    func: F
) -> Result<Function<'lua>> where
    'lua: 'callback,
    A: FromLuaMulti<'callback>,
    R: ToLuaMulti<'callback>,
    F: 'static + MaybeSend + Fn(&'callback Lua, A) -> Result<R>

So it's pretty clear:

  • the returned Function can contain references into self (they are tied together using the 'lua lifetime);
  • the Rust-level function itself needs to be 'static, i.e. globally-storable, ergo it must not contain any temporary references.

You don't show how sum and sum_callback are defined, but my guess would be that the reason why you get this particular lifetime error is that they are closures that capture local variables by reference, which is exactly the kind of thing the 'static bound forbids.

My apologies, I should have removed

    // globals.set("sum", lua.create_function(sum)?)?;
    // globals.set("sumcb", lua.create_function(sum_callback)?)?;

for the sake of clarity - these were older (successful) tests, and no longer exist in the code.
They are commented out because they are no longer in use - so they're not causing the lifetime error.

The lifetime error is on add_field_method_set.

However, you've said it should be clear from the function definition that those lifetime relations follow, and that's not clear to me, so I don't think I have a good grasp on the lifetime definitions -
This is likely the root of my issue with add_field_method_set as well, so I'll see what I can find on the topic.

Cheers!

I think the problem is even simpler in that case. You are implementing the trait for CallbackHolder<'static>, which means that this.event_handler has type Option<LuaFunction<'static>>. However, based on the signature of add_field_method_set, there's nothing requiring that the 3rd parameter of the callback should be 'static, so I don't think you can write such an impl.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.