-
| are there any best-practices for minimizing overhead for calling back into a rust library from lua(u)? I have a setup that will be making 100's of millions of small calls. | 
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 19 replies
-
| Try to avoid setting fields on UserData object. The fastest way is UserData with methods only. | 
Beta Was this translation helpful? Give feedback.
-
| oh, indeed that's much faster on my quick test. It gave a 4X speed improvement. Now a naive question, with that change, the syntax for my user expressions go from: I am guessing not from looking at docs here but wanted to be sure. | 
Beta Was this translation helpful? Give feedback.
-
| Actually, I notice if I have a single method vs a single field, the performance difference is negligible. I assume the difference is more when there are more fields vs more methods? Comparing a single field to ~15 field, I see a dramatic performance improvement when only a single field is specified (using same expression on only that single field). | 
Beta Was this translation helpful? Give feedback.
-
| 
 It should not really matter, the complexity is O(1), fields and methods are stored in a hashmap. 
 You can try to set  fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
    fields.add_meta_field_with("__index", |lua| {
        lua.create_function(
            |lua, (this, key): (mlua::UserDataRef<Self>, mlua::String)| match key.as_bytes() {
                b"field" => Ok(this.field),
                _ => Err(mlua::Error::RuntimeError("no such field".to_string())),
            },
        )
    })
} | 
Beta Was this translation helpful? Give feedback.
-
| I tried userdata_ref with only the Record struct (no Alignment) here Unless there's an obvious way to fix this I will try again to use your other suggestion: fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
    fields.add_meta_field_with("__index", |lua| {
        lua.create_function(
            |lua, (this, key): (mlua::UserDataRef<Self>, mlua::String)| match key.as_bytes() {
                b"field" => Ok(this.field),
                _ => Err(mlua::Error::RuntimeError("no such field".to_string())),
            },
        )
    })
}since that will limit the number of fields that need to be copied for non_static_userdata. | 
Beta Was this translation helpful? Give feedback.
-
| If I have something like this (with __index): fn register_variant(lua: &Lua) -> mlua::Result<()> {
    lua.register_userdata_type::<Variant>(|reg| {
        reg.add_meta_function(
            MetaMethod::Index,
            |_lua, (_, name): (AnyUserData, String)| {
                let msg = format!("field '{}' variant.{} not found", name, name);
                Err::<LuaValue<'_>, mlua::Error>(mlua::Error::RuntimeError(msg))
            },
        );
      ... // other reg.add_field_method_get definitions
}I just want to give an error if the user access an unset field (rather than returning nil). | 
Beta Was this translation helpful? Give feedback.
-
| ok. Thanks @khvzak . I benchmarked it and the difference is minimal for a typical use-case so I'll leave it for now. Another question. I have this:         reg.add_field_method_get("id", |lua: &Lua, this: &Variant| {
            let id = this.0.id();
            Ok(Value::String(unsafe {
                lua.create_string(String::from_utf8_unchecked(id.to_vec()))?
            }))
        });
        reg.add_field_method_set(
            "id",
            |_lua: &Lua, this: &mut Variant, val: String| match this.0.set_id(val.as_bytes()) {
                Err(e) => Err(mlua::Error::ExternalError(Arc::new(e))),
                Ok(_) => Ok(()),
            },
        );and I can read  Any pointers here? I am using:       let ud = scope.create_any_userdata_ref(variant)?;
      globals.set("variant", ud)?; | 
Beta Was this translation helpful? Give feedback.
-
| here is a full example: https://github.com/brentp/help-repositories/blob/1a6a22ff264e2042794f539cd9527b71b12c9188/src/main.rs#L48-L57 it seems to find the getters before __index, but not the setters before __newindex. | 
Beta Was this translation helpful? Give feedback.
-
| I know things have changed in v0.10+, is  | 
Beta Was this translation helpful? Give feedback.
It should not really matter, the complexity is O(1), fields and methods are stored in a hashmap.
However Luau at compile time can predict hashmap slot when userdata has only methods. Whereas with fields(+ methods) lookup is always dynamic.
You can try to set
__indexmetamethod for your case: