Merge pull request #32 from chucklefish/tuples
Major API changes before 0.9
This commit is contained in:
commit
64ac8b4679
|
@ -20,6 +20,3 @@ builtin-lua = ["gcc"]
|
|||
|
||||
[build-dependencies]
|
||||
gcc = { version = "0.3", optional = true }
|
||||
|
||||
[dependencies]
|
||||
hlist-macro = "0.1"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#[macro_use]
|
||||
extern crate hlist_macro;
|
||||
extern crate rlua;
|
||||
|
||||
use std::f32;
|
||||
|
@ -79,40 +77,28 @@ fn examples() -> Result<()> {
|
|||
let print: Function = globals.get("print")?;
|
||||
print.call::<_, ()>("hello from rust")?;
|
||||
|
||||
// This API handles variadics using Heterogeneous Lists. This is one way to
|
||||
// call a function with multiple parameters:
|
||||
// This API handles variadics using tuples. This is one way to call a function with multiple
|
||||
// parameters:
|
||||
|
||||
print.call::<_, ()>(
|
||||
hlist!["hello", "again", "from", "rust"],
|
||||
)?;
|
||||
print.call::<_, ()>(("hello", "again", "from", "rust"))?;
|
||||
|
||||
// You can bind rust functions to lua as well
|
||||
|
||||
let check_equal = lua.create_function(|lua, args| {
|
||||
// Functions wrapped in lua receive their arguments packed together as
|
||||
// MultiValue. The first thing that most wrapped functions will do
|
||||
// is "unpack" this MultiValue into its parts. Due to lifetime type
|
||||
// signature limitations, this cannot be done automatically from the
|
||||
// function signature, but this will be fixed with ATCs. Notice the use
|
||||
// of the hlist macros again.
|
||||
let hlist_pat![list1, list2] = lua.unpack::<HList![Vec<String>, Vec<String>]>(args)?;
|
||||
|
||||
// This function just checks whether two string lists are equal, and in
|
||||
// an inefficient way. Results are returned with lua.pack, which takes
|
||||
// any number of values and turns them back into MultiValue. In this
|
||||
// way, multiple values can also be returned to Lua. Again, this cannot
|
||||
// be inferred as part of the function signature due to the same
|
||||
// lifetime type signature limitations.
|
||||
lua.pack(list1 == list2)
|
||||
// You can bind rust functions to lua as well. Callbacks receive the lua state itself as their
|
||||
// first parameter, and the arguments given to the function as the second parameter. The type
|
||||
// of the arguments can be anything that is convertible from the set of parameters, in this
|
||||
// case, the function expects two string sequences.
|
||||
let check_equal = lua.create_function(|_, (list1, list2): (Vec<String>, Vec<String>)| {
|
||||
// This function just checks whether two string lists are equal, and in an inefficient way.
|
||||
// Lua callbacks return rlua::Result, an Ok value is a normal return, and an Err return
|
||||
// turns into a Lua 'error'. Again, any type that is convertible to lua may be returned.
|
||||
Ok(list1 == list2)
|
||||
});
|
||||
globals.set("check_equal", check_equal)?;
|
||||
|
||||
// You can also accept variadic arguments to rust callbacks.
|
||||
// You can also accept runtime variadic arguments to rust callbacks.
|
||||
|
||||
let join = lua.create_function(|lua, args| {
|
||||
let strings = lua.unpack::<Variadic<String>>(args)?.0;
|
||||
let join = lua.create_function(|_, strings: Variadic<String>| {
|
||||
// (This is quadratic!, it's just an example!)
|
||||
lua.pack(strings.iter().fold("".to_owned(), |a, b| a + b))
|
||||
Ok(strings.iter().fold("".to_owned(), |a, b| a + b))
|
||||
});
|
||||
globals.set("join", join)?;
|
||||
|
||||
|
@ -141,22 +127,18 @@ fn examples() -> Result<()> {
|
|||
|
||||
impl UserData for Vec2 {
|
||||
fn add_methods(methods: &mut UserDataMethods<Self>) {
|
||||
methods.add_method("magnitude", |lua, vec, _| {
|
||||
methods.add_method("magnitude", |_, vec, ()| {
|
||||
let mag_squared = vec.0 * vec.0 + vec.1 * vec.1;
|
||||
lua.pack(mag_squared.sqrt())
|
||||
Ok(mag_squared.sqrt())
|
||||
});
|
||||
|
||||
methods.add_meta_function(MetaMethod::Add, |lua, params| {
|
||||
let hlist_pat![vec1, vec2] = lua.unpack::<HList![Vec2, Vec2]>(params)?;
|
||||
lua.pack(Vec2(vec1.0 + vec2.0, vec1.1 + vec2.1))
|
||||
methods.add_meta_function(MetaMethod::Add, |_, (vec1, vec2): (Vec2, Vec2)| {
|
||||
Ok(Vec2(vec1.0 + vec2.0, vec1.1 + vec2.1))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let vec2_constructor = lua.create_function(|lua, args| {
|
||||
let hlist_pat![x, y] = lua.unpack::<HList![f32, f32]>(args)?;
|
||||
lua.pack(Vec2(x, y))
|
||||
});
|
||||
let vec2_constructor = lua.create_function(|_, (x, y): (f32, f32)| Ok(Vec2(x, y)));
|
||||
globals.set("vec2", vec2_constructor)?;
|
||||
|
||||
assert!(
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
// Deny warnings inside doc tests / examples
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
||||
#[cfg_attr(test, macro_use)]
|
||||
extern crate hlist_macro;
|
||||
|
||||
pub mod ffi;
|
||||
#[macro_use]
|
||||
mod util;
|
||||
|
|
146
src/lua.rs
146
src/lua.rs
|
@ -39,12 +39,10 @@ pub enum Value<'lua> {
|
|||
Function(Function<'lua>),
|
||||
/// Reference to a Lua thread (or coroutine).
|
||||
Thread(Thread<'lua>),
|
||||
/// Reference to a userdata object that holds a custom type which implements
|
||||
/// `UserData`. Special builtin userdata types will be represented as
|
||||
/// other `Value` variants.
|
||||
/// Reference to a userdata object that holds a custom type which implements `UserData`.
|
||||
/// Special builtin userdata types will be represented as other `Value` variants.
|
||||
UserData(AnyUserData<'lua>),
|
||||
/// `Error` is a special builtin userdata type. When received from Lua
|
||||
/// it is implicitly cloned.
|
||||
/// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
|
||||
Error(Error),
|
||||
}
|
||||
pub use self::Value::Nil;
|
||||
|
@ -647,7 +645,6 @@ impl<'lua> Function<'lua> {
|
|||
///
|
||||
/// ```
|
||||
/// # extern crate rlua;
|
||||
/// # #[macro_use] extern crate hlist_macro;
|
||||
/// # use rlua::{Lua, Function, Result};
|
||||
/// # fn try_main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
|
@ -658,7 +655,7 @@ impl<'lua> Function<'lua> {
|
|||
/// end
|
||||
/// "#, None)?;
|
||||
///
|
||||
/// assert_eq!(sum.call::<_, u32>(hlist![3, 4])?, 3 + 4);
|
||||
/// assert_eq!(sum.call::<_, u32>((3, 4))?, 3 + 4);
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
|
@ -966,9 +963,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
///
|
||||
/// If `add_meta_method` is used to override the `__index` metamethod, this approach will fall
|
||||
/// back to the user-provided metamethod if no regular method was found.
|
||||
pub fn add_method<M>(&mut self, name: &str, method: M)
|
||||
pub fn add_method<A, R, M>(&mut self, name: &str, method: M)
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, A) -> Result<R>,
|
||||
{
|
||||
self.methods.insert(
|
||||
name.to_owned(),
|
||||
|
@ -981,9 +980,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
/// Refer to [`add_method`] for more information about the implementation.
|
||||
///
|
||||
/// [`add_method`]: #method.add_method
|
||||
pub fn add_method_mut<M>(&mut self, name: &str, method: M)
|
||||
pub fn add_method_mut<A, R, M>(&mut self, name: &str, method: M)
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, A) -> Result<R>,
|
||||
{
|
||||
self.methods.insert(
|
||||
name.to_owned(),
|
||||
|
@ -998,11 +999,16 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
///
|
||||
/// [`add_method`]: #method.add_method
|
||||
/// [`add_method_mut`]: #method.add_method_mut
|
||||
pub fn add_function<F>(&mut self, name: &str, function: F)
|
||||
pub fn add_function<A, R, F>(&mut self, name: &str, function: F)
|
||||
where
|
||||
F: 'static + FnMut(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.methods.insert(name.to_owned(), Box::new(function));
|
||||
self.methods.insert(
|
||||
name.to_owned(),
|
||||
Self::box_function(function),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add a metamethod which accepts a `&T` as the first parameter.
|
||||
|
@ -1013,9 +1019,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
/// side has a metatable. To prevent this, use [`add_meta_function`].
|
||||
///
|
||||
/// [`add_meta_function`]: #method.add_meta_function
|
||||
pub fn add_meta_method<M>(&mut self, meta: MetaMethod, method: M)
|
||||
pub fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.insert(meta, Self::box_method(method));
|
||||
}
|
||||
|
@ -1028,9 +1036,11 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
/// side has a metatable. To prevent this, use [`add_meta_function`].
|
||||
///
|
||||
/// [`add_meta_function`]: #method.add_meta_function
|
||||
pub fn add_meta_method_mut<M>(&mut self, meta: MetaMethod, method: M)
|
||||
pub fn add_meta_method_mut<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.insert(meta, Self::box_method_mut(method));
|
||||
}
|
||||
|
@ -1040,21 +1050,39 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
/// Metamethods for binary operators can be triggered if either the left or right argument to
|
||||
/// the binary operator has a metatable, so the first argument here is not necessarily a
|
||||
/// userdata of type `T`.
|
||||
pub fn add_meta_function<F>(&mut self, meta: MetaMethod, function: F)
|
||||
pub fn add_meta_function<A, R, F>(&mut self, meta: MetaMethod, function: F)
|
||||
where
|
||||
F: 'static + FnMut(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.insert(meta, Box::new(function));
|
||||
self.meta_methods.insert(meta, Self::box_function(function));
|
||||
}
|
||||
|
||||
fn box_method<M>(mut method: M) -> Callback<'lua>
|
||||
fn box_function<A, R, F>(mut function: F) -> Callback<'lua>
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + for<'a> FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, args| {
|
||||
function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(
|
||||
lua,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn box_method<A, R, M>(mut method: M) -> Callback<'lua>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a T, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
||||
let userdata = AnyUserData::from_lua(front, lua)?;
|
||||
let userdata = userdata.borrow::<T>()?;
|
||||
method(lua, &userdata, args)
|
||||
method(lua, &userdata, A::from_lua_multi(args, lua)?)?
|
||||
.to_lua_multi(lua)
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError(
|
||||
"No userdata supplied as first argument to method"
|
||||
|
@ -1063,14 +1091,17 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
})
|
||||
}
|
||||
|
||||
fn box_method_mut<M>(mut method: M) -> Callback<'lua>
|
||||
fn box_method_mut<A, R, M>(mut method: M) -> Callback<'lua>
|
||||
where
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + for<'a> FnMut(&'lua Lua, &'a mut T, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
||||
let userdata = AnyUserData::from_lua(front, lua)?;
|
||||
let mut userdata = userdata.borrow_mut::<T>()?;
|
||||
method(lua, &mut userdata, args)
|
||||
method(lua, &mut userdata, A::from_lua_multi(args, lua)?)?
|
||||
.to_lua_multi(lua)
|
||||
} else {
|
||||
Err(
|
||||
Error::FromLuaConversionError(
|
||||
|
@ -1078,7 +1109,6 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
).into(),
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1121,21 +1151,17 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> {
|
|||
///
|
||||
/// impl UserData for MyUserData {
|
||||
/// fn add_methods(methods: &mut UserDataMethods<Self>) {
|
||||
/// methods.add_method("get", |lua, this, args| {
|
||||
/// # let _ = (lua, args); // used
|
||||
/// lua.pack(this.0)
|
||||
/// methods.add_method("get", |_, this, _: ()| {
|
||||
/// Ok(this.0)
|
||||
/// });
|
||||
///
|
||||
/// methods.add_method_mut("add", |lua, this, args| {
|
||||
/// let value: i32 = lua.unpack(args)?;
|
||||
///
|
||||
/// methods.add_method_mut("add", |_, this, value: i32| {
|
||||
/// this.0 += value;
|
||||
/// lua.pack(())
|
||||
/// Ok(())
|
||||
/// });
|
||||
///
|
||||
/// methods.add_meta_method(MetaMethod::Add, |lua, this, args| {
|
||||
/// let value: i32 = lua.unpack(args)?;
|
||||
/// lua.pack(this.0 + value)
|
||||
/// methods.add_meta_method(MetaMethod::Add, |_, this, value: i32| {
|
||||
/// Ok(this.0 + value)
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
|
@ -1478,10 +1504,9 @@ impl Lua {
|
|||
/// # fn try_main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
///
|
||||
/// let greet = lua.create_function(|lua, args| {
|
||||
/// let name: String = lua.unpack(args)?;
|
||||
/// let greet = lua.create_function(|_, name: String| {
|
||||
/// println!("Hello, {}!", name);
|
||||
/// lua.pack(())
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// # let _ = greet; // used
|
||||
/// # Ok(())
|
||||
|
@ -1491,19 +1516,17 @@ impl Lua {
|
|||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Use the `hlist_macro` crate to use multiple arguments:
|
||||
/// Use tuples to accept multiple arguments:
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use] extern crate hlist_macro;
|
||||
/// # extern crate rlua;
|
||||
/// # use rlua::{Lua, Result};
|
||||
/// # fn try_main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
///
|
||||
/// let print_person = lua.create_function(|lua, args| {
|
||||
/// let hlist_pat![name, age]: HList![String, u8] = lua.unpack(args)?;
|
||||
/// let print_person = lua.create_function(|_, (name, age): (String, u8)| {
|
||||
/// println!("{} is {} years old!", name, age);
|
||||
/// lua.pack(())
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// # let _ = print_person; // used
|
||||
/// # Ok(())
|
||||
|
@ -1512,11 +1535,15 @@ impl Lua {
|
|||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn create_function<'lua, F>(&'lua self, func: F) -> Function<'lua>
|
||||
pub fn create_function<'lua, A, R, F>(&'lua self, mut func: F) -> Function<'lua>
|
||||
where
|
||||
F: 'static + FnMut(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.create_callback_function(Box::new(func))
|
||||
self.create_callback_function(Box::new(move |lua, args| {
|
||||
func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}))
|
||||
}
|
||||
|
||||
/// Wraps a Lua function into a new thread (or coroutine).
|
||||
|
@ -1645,25 +1672,26 @@ impl Lua {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<Value<'lua>> {
|
||||
/// Converts a value that implements `ToLua` into a `Value` instance.
|
||||
pub fn pack<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<Value<'lua>> {
|
||||
t.to_lua(self)
|
||||
}
|
||||
|
||||
pub fn to<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> {
|
||||
/// Converts a `Value` instance into a value that implements `FromLua`.
|
||||
pub fn unpack<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> {
|
||||
T::from_lua(value, self)
|
||||
}
|
||||
|
||||
/// Packs up a value that implements `ToLuaMulti` into a `MultiValue` instance.
|
||||
///
|
||||
/// This can be used to return arbitrary Lua values from a Rust function back to Lua.
|
||||
pub fn pack<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> Result<MultiValue<'lua>> {
|
||||
/// Converts a value that implements `ToLuaMulti` into a `MultiValue` instance.
|
||||
pub fn pack_multi<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> Result<MultiValue<'lua>> {
|
||||
t.to_lua_multi(self)
|
||||
}
|
||||
|
||||
/// Unpacks a `MultiValue` instance into a value that implements `FromLuaMulti`.
|
||||
///
|
||||
/// This can be used to convert the arguments of a Rust function called by Lua.
|
||||
pub fn unpack<'lua, T: FromLuaMulti<'lua>>(&'lua self, value: MultiValue<'lua>) -> Result<T> {
|
||||
/// Converts a `MultiValue` instance into a value that implements `FromLuaMulti`.
|
||||
pub fn unpack_multi<'lua, T: FromLuaMulti<'lua>>(
|
||||
&'lua self,
|
||||
value: MultiValue<'lua>,
|
||||
) -> Result<T> {
|
||||
T::from_lua_multi(value, self)
|
||||
}
|
||||
|
||||
|
|
165
src/multi.rs
165
src/multi.rs
|
@ -1,22 +1,10 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use std::iter::FromIterator;
|
||||
use std::result::Result as StdResult;
|
||||
|
||||
use hlist_macro::{HNil, HCons};
|
||||
|
||||
use error::*;
|
||||
use lua::*;
|
||||
|
||||
impl<'lua> ToLuaMulti<'lua> for () {
|
||||
fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue> {
|
||||
Ok(MultiValue::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for () {
|
||||
fn from_lua_multi(_: MultiValue, _: &'lua Lua) -> Result<Self> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Result is convertible to `MultiValue` following the common lua idiom of returning the result
|
||||
/// on success, or in the case of an error, returning nil followed by the error
|
||||
impl<'lua, T: ToLua<'lua>, E: ToLua<'lua>> ToLuaMulti<'lua> for StdResult<T, E> {
|
||||
|
@ -63,9 +51,45 @@ impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
|
|||
|
||||
/// Can be used to pass variadic values to or receive variadic values from Lua, where the type of
|
||||
/// the values is all the same and the number of values is defined at runtime. This can be included
|
||||
/// in an hlist when unpacking, but must be the final entry, and will consume the rest of the
|
||||
/// in tuple when unpacking, but must be the final entry, and will consume the rest of the
|
||||
/// parameters given.
|
||||
pub struct Variadic<T>(pub Vec<T>);
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Variadic<T>(Vec<T>);
|
||||
|
||||
impl<T> Variadic<T> {
|
||||
pub fn new() -> Variadic<T> {
|
||||
Variadic(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromIterator<T> for Variadic<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
Variadic(Vec::from_iter(iter))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for Variadic<T> {
|
||||
type Item = T;
|
||||
type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Variadic<T> {
|
||||
type Target = Vec<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Variadic<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for Variadic<T> {
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
|
@ -83,48 +107,75 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> ToLuaMulti<'lua> for HNil {
|
||||
fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
Ok(MultiValue::new())
|
||||
}
|
||||
macro_rules! impl_tuple {
|
||||
() => (
|
||||
impl<'lua> ToLuaMulti<'lua> for () {
|
||||
fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue> {
|
||||
Ok(MultiValue::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for () {
|
||||
fn from_lua_multi(_: MultiValue, _: &'lua Lua) -> Result<Self> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
($last:ident $($name:ident)*) => (
|
||||
impl<'lua, $($name,)* $last> ToLuaMulti<'lua> for ($($name,)* $last,)
|
||||
where $($name: ToLua<'lua>,)*
|
||||
$last: ToLuaMulti<'lua>
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
#[allow(non_snake_case)]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let ($($name,)* $last,) = self;
|
||||
|
||||
let mut results = $last.to_lua_multi(lua)?;
|
||||
push_reverse!(results, $($name.to_lua(lua)?,)*);
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,)
|
||||
where $($name: FromLua<'lua>,)*
|
||||
$last: FromLuaMulti<'lua>
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
#[allow(non_snake_case)]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
$(let $name = values.pop_front().unwrap_or(Nil);)*
|
||||
let $last = FromLuaMulti::from_lua_multi(values, lua)?;
|
||||
Ok(($(FromLua::from_lua($name, lua)?,)* $last,))
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for HNil {
|
||||
fn from_lua_multi(_: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
Ok(HNil)
|
||||
}
|
||||
macro_rules! push_reverse {
|
||||
($multi_value:expr, $first:expr, $($rest:expr,)*) => (
|
||||
push_reverse!($multi_value, $($rest,)*);
|
||||
$multi_value.push_front($first);
|
||||
);
|
||||
|
||||
($multi_value:expr, $first:expr) => (
|
||||
$multi_value.push_front($first);
|
||||
);
|
||||
|
||||
($multi_value:expr,) => ();
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLuaMulti<'lua>> ToLuaMulti<'lua> for HCons<T, HNil> {
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
self.0.to_lua_multi(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLuaMulti<'lua>> FromLuaMulti<'lua> for HCons<T, HNil> {
|
||||
fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
Ok(HCons(T::from_lua_multi(values, lua)?, HNil))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, H: ToLua<'lua>, A, B> ToLuaMulti<'lua> for HCons<H, HCons<A, B>>
|
||||
where
|
||||
HCons<A, B>: ToLuaMulti<'lua>,
|
||||
{
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let mut results = self.1.to_lua_multi(lua)?;
|
||||
results.push_front(self.0.to_lua(lua)?);
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, H: FromLua<'lua>, A, B> FromLuaMulti<'lua> for HCons<H, HCons<A, B>>
|
||||
where
|
||||
HCons<A, B>: FromLuaMulti<'lua>,
|
||||
{
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let val = H::from_lua(values.pop_front().unwrap_or(Nil), lua)?;
|
||||
let res = HCons::<A, B>::from_lua_multi(values, lua)?;
|
||||
Ok(HCons(val, res))
|
||||
}
|
||||
}
|
||||
impl_tuple!{}
|
||||
impl_tuple!{A}
|
||||
impl_tuple!{A B}
|
||||
impl_tuple!{A B C}
|
||||
impl_tuple!{A B C D}
|
||||
impl_tuple!{A B C D E}
|
||||
impl_tuple!{A B C D E F}
|
||||
impl_tuple!{A B C D E F G}
|
||||
impl_tuple!{A B C D E F G H}
|
||||
impl_tuple!{A B C D E F G H I}
|
||||
impl_tuple!{A B C D E F G H I J}
|
||||
impl_tuple!{A B C D E F G H I J K}
|
||||
impl_tuple!{A B C D E F G H I J K L}
|
||||
|
|
99
src/tests.rs
99
src/tests.rs
|
@ -173,10 +173,7 @@ fn test_function() {
|
|||
).unwrap();
|
||||
|
||||
let concat = globals.get::<_, Function>("concat").unwrap();
|
||||
assert_eq!(
|
||||
concat.call::<_, String>(hlist!["foo", "bar"]).unwrap(),
|
||||
"foobar"
|
||||
);
|
||||
assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -199,9 +196,9 @@ fn test_bind() {
|
|||
let mut concat = globals.get::<_, Function>("concat").unwrap();
|
||||
concat = concat.bind("foo").unwrap();
|
||||
concat = concat.bind("bar").unwrap();
|
||||
concat = concat.bind(hlist!["baz", "baf"]).unwrap();
|
||||
concat = concat.bind(("baz", "baf")).unwrap();
|
||||
assert_eq!(
|
||||
concat.call::<_, String>(hlist!["hi", "wut"]).unwrap(),
|
||||
concat.call::<_, String>(("hi", "wut")).unwrap(),
|
||||
"foobarbazbafhiwut"
|
||||
);
|
||||
}
|
||||
|
@ -223,9 +220,7 @@ fn test_rust_function() {
|
|||
).unwrap();
|
||||
|
||||
let lua_function = globals.get::<_, Function>("lua_function").unwrap();
|
||||
let rust_function = lua.create_function(|lua, _| {
|
||||
lua.pack("hello")
|
||||
});
|
||||
let rust_function = lua.create_function(|_, ()| Ok("hello"));
|
||||
|
||||
globals.set("rust_function", rust_function).unwrap();
|
||||
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
|
||||
|
@ -259,10 +254,10 @@ fn test_methods() {
|
|||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods(methods: &mut UserDataMethods<Self>) {
|
||||
methods.add_method("get_value", |lua, data, _| lua.pack(data.0));
|
||||
methods.add_method_mut("set_value", |lua, data, args| {
|
||||
data.0 = lua.unpack(args)?;
|
||||
lua.pack(())
|
||||
methods.add_method("get_value", |_, data, ()| Ok(data.0));
|
||||
methods.add_method_mut("set_value", |_, data, args| {
|
||||
data.0 = args;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -299,23 +294,21 @@ fn test_metamethods() {
|
|||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods(methods: &mut UserDataMethods<Self>) {
|
||||
methods.add_method("get", |lua, data, _| lua.pack(data.0));
|
||||
methods.add_meta_function(MetaMethod::Add, |lua, args| {
|
||||
let hlist_pat![lhs, rhs] = lua.unpack::<HList![MyUserData, MyUserData]>(args)?;
|
||||
lua.pack(MyUserData(lhs.0 + rhs.0))
|
||||
methods.add_method("get", |_, data, ()| Ok(data.0));
|
||||
methods.add_meta_function(MetaMethod::Add, |_, (lhs, rhs): (MyUserData, MyUserData)| {
|
||||
Ok(MyUserData(lhs.0 + rhs.0))
|
||||
});
|
||||
methods.add_meta_function(MetaMethod::Sub, |lua, args| {
|
||||
let hlist_pat![lhs, rhs] = lua.unpack::<HList![MyUserData, MyUserData]>(args)?;
|
||||
lua.pack(MyUserData(lhs.0 - rhs.0))
|
||||
methods.add_meta_function(MetaMethod::Sub, |_, (lhs, rhs): (MyUserData, MyUserData)| {
|
||||
Ok(MyUserData(lhs.0 - rhs.0))
|
||||
});
|
||||
methods.add_meta_method(MetaMethod::Index, |lua, data, args| {
|
||||
let index = lua.unpack::<LuaString>(args)?;
|
||||
if index.to_str()? == "inner" {
|
||||
lua.pack(data.0)
|
||||
methods.add_meta_method(
|
||||
MetaMethod::Index,
|
||||
|_, data, index: LuaString| if index.to_str()? == "inner" {
|
||||
Ok(data.0)
|
||||
} else {
|
||||
Err("no such custom index".to_lua_err())
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,16 +378,12 @@ fn test_lua_multi() {
|
|||
let concat = globals.get::<_, Function>("concat").unwrap();
|
||||
let mreturn = globals.get::<_, Function>("mreturn").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
concat.call::<_, String>(hlist!["foo", "bar"]).unwrap(),
|
||||
"foobar"
|
||||
);
|
||||
let hlist_pat![a, b] = mreturn.call::<_, HList![u64, u64]>(hlist![]).unwrap();
|
||||
assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar");
|
||||
let (a, b) = mreturn.call::<_, (u64, u64)>(()).unwrap();
|
||||
assert_eq!((a, b), (1, 2));
|
||||
let hlist_pat![a, b, Variadic(v)] =
|
||||
mreturn.call::<_, HList![u64, u64, Variadic<u64>]>(hlist![]).unwrap();
|
||||
let (a, b, v) = mreturn.call::<_, (u64, u64, Variadic<u64>)>(()).unwrap();
|
||||
assert_eq!((a, b), (1, 2));
|
||||
assert_eq!(v, vec![3, 4, 5, 6]);
|
||||
assert_eq!(v[..], [3, 4, 5, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -491,7 +480,8 @@ fn test_error() {
|
|||
None,
|
||||
).unwrap();
|
||||
|
||||
let rust_error_function = lua.create_function(|_, _| Err(TestError.to_lua_err()));
|
||||
let rust_error_function =
|
||||
lua.create_function(|_, ()| -> Result<()> { Err(TestError.to_lua_err()) });
|
||||
globals
|
||||
.set("rust_error_function", rust_error_function)
|
||||
.unwrap();
|
||||
|
@ -550,7 +540,7 @@ fn test_error() {
|
|||
"#,
|
||||
None,
|
||||
)?;
|
||||
let rust_panic_function = lua.create_function(|_, _| {
|
||||
let rust_panic_function = lua.create_function(|_, ()| -> Result<()> {
|
||||
panic!("expected panic, this panic should be caught in rust")
|
||||
});
|
||||
globals.set("rust_panic_function", rust_panic_function)?;
|
||||
|
@ -576,7 +566,7 @@ fn test_error() {
|
|||
"#,
|
||||
None,
|
||||
)?;
|
||||
let rust_panic_function = lua.create_function(|_, _| {
|
||||
let rust_panic_function = lua.create_function(|_, ()| -> Result<()> {
|
||||
panic!("expected panic, this panic should be caught in rust")
|
||||
});
|
||||
globals.set("rust_panic_function", rust_panic_function)?;
|
||||
|
@ -733,12 +723,12 @@ fn test_result_conversions() {
|
|||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
let err = lua.create_function(|lua, _| {
|
||||
lua.pack(Err::<String, _>(
|
||||
let err = lua.create_function(|_, ()| {
|
||||
Ok(Err::<String, _>(
|
||||
"only through failure can we succeed".to_lua_err(),
|
||||
))
|
||||
});
|
||||
let ok = lua.create_function(|lua, _| lua.pack(Ok::<_, Error>("!".to_owned())));
|
||||
let ok = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned())));
|
||||
|
||||
globals.set("err", err).unwrap();
|
||||
globals.set("ok", ok).unwrap();
|
||||
|
@ -790,9 +780,9 @@ fn test_expired_userdata() {
|
|||
|
||||
impl UserData for MyUserdata {
|
||||
fn add_methods(methods: &mut UserDataMethods<Self>) {
|
||||
methods.add_method("access", |lua, this, _| {
|
||||
methods.add_method("access", |_, this, ()| {
|
||||
assert!(this.id == 123);
|
||||
lua.pack(())
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -851,17 +841,26 @@ fn detroys_userdata() {
|
|||
#[test]
|
||||
fn string_views() {
|
||||
let lua = Lua::new();
|
||||
lua.eval::<()>(r#"
|
||||
lua.eval::<()>(
|
||||
r#"
|
||||
ok = "null bytes are valid utf-8, wh\0 knew?"
|
||||
err = "but \xff isn't :("
|
||||
"#, None).unwrap();
|
||||
"#,
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
let globals = lua.globals();
|
||||
let ok: LuaString = globals.get("ok").unwrap();
|
||||
let err: LuaString = globals.get("err").unwrap();
|
||||
|
||||
assert_eq!(ok.to_str().unwrap(), "null bytes are valid utf-8, wh\0 knew?");
|
||||
assert_eq!(ok.as_bytes(), &b"null bytes are valid utf-8, wh\0 knew?"[..]);
|
||||
assert_eq!(
|
||||
ok.to_str().unwrap(),
|
||||
"null bytes are valid utf-8, wh\0 knew?"
|
||||
);
|
||||
assert_eq!(
|
||||
ok.as_bytes(),
|
||||
&b"null bytes are valid utf-8, wh\0 knew?"[..]
|
||||
);
|
||||
|
||||
assert!(err.to_str().is_err());
|
||||
assert_eq!(err.as_bytes(), &b"but \xff isn't :("[..]);
|
||||
|
@ -870,9 +869,7 @@ fn string_views() {
|
|||
#[test]
|
||||
fn coroutine_from_closure() {
|
||||
let lua = Lua::new();
|
||||
let thrd_main = lua.create_function(|lua, _| {
|
||||
lua.pack(())
|
||||
});
|
||||
let thrd_main = lua.create_function(|_, ()| Ok(()));
|
||||
lua.globals().set("main", thrd_main).unwrap();
|
||||
let thrd: Thread = lua.eval("coroutine.create(main)", None).unwrap();
|
||||
thrd.resume::<_, ()>(()).unwrap();
|
||||
|
@ -882,10 +879,10 @@ fn coroutine_from_closure() {
|
|||
#[should_panic]
|
||||
fn coroutine_panic() {
|
||||
let lua = Lua::new();
|
||||
let thrd_main = lua.create_function(|lua, _| {
|
||||
let thrd_main = lua.create_function(|lua, ()| {
|
||||
// whoops, 'main' has a wrong type
|
||||
let _coro: u32 = lua.globals().get("main").unwrap();
|
||||
lua.pack(())
|
||||
Ok(())
|
||||
});
|
||||
lua.globals().set("main", thrd_main.clone()).unwrap();
|
||||
let thrd: Thread = lua.create_thread(thrd_main);
|
||||
|
|
Loading…
Reference in New Issue