Allow callback functions to have 'lua lifetime rather than 'static
Fixes #14
This commit is contained in:
parent
6df96d8eb1
commit
5b723d58be
56
src/lua.rs
56
src/lua.rs
|
@ -124,10 +124,8 @@ pub trait FromLuaMulti<'a>: Sized {
|
||||||
fn from_lua_multi(values: LuaMultiValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
fn from_lua_multi(values: LuaMultiValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LuaCallback = Box<
|
type LuaCallback<'lua> =
|
||||||
for<'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
Box<'lua + FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>>;
|
||||||
-> LuaResult<LuaMultiValue<'lua>>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
struct LuaRef<'lua> {
|
struct LuaRef<'lua> {
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
|
@ -758,17 +756,17 @@ pub enum LuaMetaMethod {
|
||||||
/// can be called as `userdata:method(args)` as expected. If there are any regular methods, and an
|
/// can be called as `userdata:method(args)` as expected. If there are any regular methods, and an
|
||||||
/// `Index` metamethod is given, it will be called as a *fallback* if the index doesn't match an
|
/// `Index` metamethod is given, it will be called as a *fallback* if the index doesn't match an
|
||||||
/// existing regular method.
|
/// existing regular method.
|
||||||
pub struct LuaUserDataMethods<T> {
|
pub struct LuaUserDataMethods<'lua, T> {
|
||||||
methods: HashMap<String, LuaCallback>,
|
methods: HashMap<String, LuaCallback<'lua>>,
|
||||||
meta_methods: HashMap<LuaMetaMethod, LuaCallback>,
|
meta_methods: HashMap<LuaMetaMethod, LuaCallback<'lua>>,
|
||||||
_type: PhantomData<T>,
|
_type: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
impl<'lua, T: LuaUserDataType> LuaUserDataMethods<'lua, T> {
|
||||||
/// Add a regular method as a function which accepts a &T as the first parameter.
|
/// Add a regular method as a function which accepts a &T as the first parameter.
|
||||||
pub fn add_method<M>(&mut self, name: &str, method: M)
|
pub fn add_method<M>(&mut self, name: &str, method: M)
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
where
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
||||||
{
|
{
|
||||||
self.methods.insert(
|
self.methods.insert(
|
||||||
name.to_owned(),
|
name.to_owned(),
|
||||||
|
@ -778,7 +776,7 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
|
|
||||||
/// Add a regular method as a function which accepts a &mut T as the first parameter.
|
/// Add a regular method as a function which accepts a &mut T as the first parameter.
|
||||||
pub fn add_method_mut<M>(&mut self, name: &str, method: M)
|
pub fn add_method_mut<M>(&mut self, name: &str, method: M)
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
-> LuaResult<LuaMultiValue<'lua>>
|
||||||
{
|
{
|
||||||
self.methods.insert(
|
self.methods.insert(
|
||||||
|
@ -790,8 +788,8 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
||||||
/// always be a LuaUserData of type T.
|
/// always be a LuaUserData of type T.
|
||||||
pub fn add_function<F>(&mut self, name: &str, function: F)
|
pub fn add_function<F>(&mut self, name: &str, function: F)
|
||||||
where F: 'static + for<'a, 'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
where
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
F: 'lua + for<'a> FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
||||||
{
|
{
|
||||||
self.methods.insert(name.to_owned(), Box::new(function));
|
self.methods.insert(name.to_owned(), Box::new(function));
|
||||||
}
|
}
|
||||||
|
@ -800,8 +798,8 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
/// error with certain binary metamethods that can trigger if ony the right side has a
|
/// error with certain binary metamethods that can trigger if ony the right side has a
|
||||||
/// metatable.
|
/// metatable.
|
||||||
pub fn add_meta_method<M>(&mut self, meta: LuaMetaMethod, method: M)
|
pub fn add_meta_method<M>(&mut self, meta: LuaMetaMethod, method: M)
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
where
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
||||||
{
|
{
|
||||||
self.meta_methods.insert(meta, Self::box_method(method));
|
self.meta_methods.insert(meta, Self::box_method(method));
|
||||||
}
|
}
|
||||||
|
@ -810,7 +808,7 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
/// cause an error with certain binary metamethods that can trigger if ony the right side has a
|
/// cause an error with certain binary metamethods that can trigger if ony the right side has a
|
||||||
/// metatable.
|
/// metatable.
|
||||||
pub fn add_meta_method_mut<M>(&mut self, meta: LuaMetaMethod, method: M)
|
pub fn add_meta_method_mut<M>(&mut self, meta: LuaMetaMethod, method: M)
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
-> LuaResult<LuaMultiValue<'lua>>
|
||||||
{
|
{
|
||||||
self.meta_methods.insert(meta, Self::box_method_mut(method));
|
self.meta_methods.insert(meta, Self::box_method_mut(method));
|
||||||
|
@ -821,15 +819,15 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
/// operator has a metatable, so the first argument here is not necessarily a userdata of type
|
/// operator has a metatable, so the first argument here is not necessarily a userdata of type
|
||||||
/// T.
|
/// T.
|
||||||
pub fn add_meta_function<F>(&mut self, meta: LuaMetaMethod, function: F)
|
pub fn add_meta_function<F>(&mut self, meta: LuaMetaMethod, function: F)
|
||||||
where F: 'static + for<'a, 'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
where
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
F: 'lua + for<'a> FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
||||||
{
|
{
|
||||||
self.meta_methods.insert(meta, Box::new(function));
|
self.meta_methods.insert(meta, Box::new(function));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_method<M>(mut method: M) -> LuaCallback
|
fn box_method<M>(mut method: M) -> LuaCallback<'lua>
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
where
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
||||||
{
|
{
|
||||||
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
||||||
let userdata = LuaUserData::from_lua(front, lua)?;
|
let userdata = LuaUserData::from_lua(front, lua)?;
|
||||||
|
@ -844,8 +842,8 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_method_mut<M>(mut method: M) -> LuaCallback
|
fn box_method_mut<M>(mut method: M) -> LuaCallback<'lua>
|
||||||
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
||||||
-> LuaResult<LuaMultiValue<'lua>>
|
-> LuaResult<LuaMultiValue<'lua>>
|
||||||
{
|
{
|
||||||
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
||||||
|
@ -869,7 +867,7 @@ pub trait LuaUserDataType: 'static + Sized {
|
||||||
fn add_methods(_methods: &mut LuaUserDataMethods<Self>) {}
|
fn add_methods(_methods: &mut LuaUserDataMethods<Self>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle to an internal Lua userdata for a type that implements LuaUserDataType. Internally,
|
/// Handle to an internal Lua userdata for a type that implements `LuaUserDataType`. Internally,
|
||||||
/// instances are stored in a `RefCell`, to best match the mutable semantics of the Lua language.
|
/// instances are stored in a `RefCell`, to best match the mutable semantics of the Lua language.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LuaUserData<'lua>(LuaRef<'lua>);
|
pub struct LuaUserData<'lua>(LuaRef<'lua>);
|
||||||
|
@ -1120,7 +1118,7 @@ impl Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a table and fills it with values from an iterator.
|
/// Creates a table and fills it with values from an iterator.
|
||||||
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> LuaResult<LuaTable>
|
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> LuaResult<LuaTable<'lua>>
|
||||||
where
|
where
|
||||||
K: ToLua<'lua>,
|
K: ToLua<'lua>,
|
||||||
V: ToLua<'lua>,
|
V: ToLua<'lua>,
|
||||||
|
@ -1142,7 +1140,7 @@ impl Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a table from an iterator of values, using `1..` as the keys.
|
/// Creates a table from an iterator of values, using `1..` as the keys.
|
||||||
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> LuaResult<LuaTable>
|
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> LuaResult<LuaTable<'lua>>
|
||||||
where
|
where
|
||||||
T: ToLua<'lua>,
|
T: ToLua<'lua>,
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
|
@ -1151,9 +1149,9 @@ impl Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
||||||
pub fn create_function<F>(&self, func: F) -> LuaFunction
|
pub fn create_function<'lua, F>(&'lua self, func: F) -> LuaFunction<'lua>
|
||||||
where
|
where
|
||||||
F: 'static + for<'a> FnMut(&'a Lua, LuaMultiValue<'a>) -> LuaResult<LuaMultiValue<'a>>,
|
F: 'lua + for<'a> FnMut(&'a Lua, LuaMultiValue<'a>) -> LuaResult<LuaMultiValue<'a>>,
|
||||||
{
|
{
|
||||||
self.create_callback_function(Box::new(func))
|
self.create_callback_function(Box::new(func))
|
||||||
}
|
}
|
||||||
|
@ -1313,7 +1311,7 @@ impl Lua {
|
||||||
T::from_lua_multi(value, self)
|
T::from_lua_multi(value, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_callback_function(&self, func: LuaCallback) -> LuaFunction {
|
fn create_callback_function<'lua>(&'lua self, func: LuaCallback<'lua>) -> LuaFunction<'lua> {
|
||||||
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
|
||||||
callback_error(state, || {
|
callback_error(state, || {
|
||||||
let lua = Lua {
|
let lua = Lua {
|
||||||
|
|
|
@ -210,6 +210,8 @@ fn test_bind() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rust_function() {
|
fn test_rust_function() {
|
||||||
|
let mut captured_var = 2;
|
||||||
|
{
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let globals = lua.globals();
|
let globals = lua.globals();
|
||||||
lua.exec::<()>(
|
lua.exec::<()>(
|
||||||
|
@ -225,11 +227,16 @@ fn test_rust_function() {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let lua_function = globals.get::<_, LuaFunction>("lua_function").unwrap();
|
let lua_function = globals.get::<_, LuaFunction>("lua_function").unwrap();
|
||||||
let rust_function = lua.create_function(|lua, _| lua.pack("hello"));
|
let rust_function = lua.create_function(|lua, _| {
|
||||||
|
captured_var = 42;
|
||||||
|
lua.pack("hello")
|
||||||
|
});
|
||||||
|
|
||||||
globals.set("rust_function", rust_function).unwrap();
|
globals.set("rust_function", rust_function).unwrap();
|
||||||
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
|
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
|
||||||
}
|
}
|
||||||
|
assert_eq!(captured_var, 42);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_user_data() {
|
fn test_user_data() {
|
||||||
|
|
Loading…
Reference in New Issue