-
The title might be a bit confusing but let's say I have this simple code: struct VecWrapper {
vec: Vec<u8>,
}
impl UserData for VecWrapper {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("vec", |_, this| Ok(this.vec.clone()));
}
}
let lua = mlua::Lua::new();
let vec_wrapper = Arc::new(Mutex::new(VecWrapper { vec: vec![0, 1] })); // `feature = ["userdata-wrappers"]`
lua.globals().set("vec_wrapper", vec_wrapper.clone())?; This code works in the sense that I can get the content of fields.add_field_method_set("vec", |_, this, v: Vec<u8>| {
this.vec = v;
Ok(())
}); quite easily. But what if I want to do: lua.load("vec_wrapper.vec[3] = 2").exec()?; ? This won't work since this is just calling the So I tought of using a custom fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method_mut("__index", |lua, this, value: String| {
Ok(match value.as_str() {
"vec" => {
if let mlua::Value::Table(table_vec) = this.vec.clone().into_lua(&lua)? {
table_vec.set_metatable(Some({
let mut t = lua.create_table()?;
t.set(
"__newindex",
Function::wrap_mut(
move |_: Table, (index, value): (usize, u8)| {
this.vec[index] = value;
Ok(())
},
),
);
t
}));
table_vec
} else {
unreachable!()
}
},
_ => todo!(),
})
});
} there are conflicts between the lifetimes of So I don't really know how you would make something like lua.load("vec_wrapper.vec[3] = 2").exec()?; work in this context. You can also put the vec in a The question is therefore: how to make the above code work ? There has been #466 as a similar discussion, but I don't think that it's really the same problem |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
There are couple of options:
impl UserData for VecWrapper {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method_mut("__index", |_, this, index: usize| Ok(this.vec.get(index).cloned()));
methods.add_meta_method_mut("__newindex", |_, this, (index, value): (usize, u8)| {
let _ = this.vec.get_mut(index).map(|slot| *slot = value);
Ok(())
});
}
}
impl UserData for VecWrapper {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_function_get("vec", |lua, this: AnyUserData| {
let t = lua.create_table()?;
let this2 = this.clone();
let get = lua.create_function(move |_, (_, index): (Table, usize)| {
let this = this2.borrow::<VecWrapper>()?;
Ok(this.vec.get(index).cloned())
})?;
let set = lua.create_function(move |_, (_, index, value): (Table, usize, u8)| {
let mut this = this.borrow_mut::<VecWrapper>()?;
if index >= this.vec.len() {
this.vec.resize(index + 1, 0);
}
this.vec[index] = value;
Ok(())
})?;
let mt = lua.create_table_from([("__index", get), ("__newindex", set)])?;
t.set_metatable(Some(mt));
Ok(t)
});
}
} |
Beta Was this translation helpful? Give feedback.
There are couple of options:
VecWrapper
acts as a vector, rather than a userdata that holds a vector.Vec<u8>
toArc<Mutex<Vec<u8>>
then consider the following trick: