Merge pull request #32 from chucklefish/tuples

Major API changes before 0.9
This commit is contained in:
kyren 2017-08-01 14:52:46 -04:00 committed by GitHub
commit 64ac8b4679
6 changed files with 263 additions and 211 deletions

View File

@ -20,6 +20,3 @@ builtin-lua = ["gcc"]
[build-dependencies]
gcc = { version = "0.3", optional = true }
[dependencies]
hlist-macro = "0.1"

View File

@ -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!(

View File

@ -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;

View File

@ -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)
}

View File

@ -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>> {
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 HNil {
fn from_lua_multi(_: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
Ok(HNil)
}
}
impl<'lua, T: ToLuaMulti<'lua>> ToLuaMulti<'lua> for HCons<T, HNil> {
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>> {
self.0.to_lua_multi(lua)
}
}
let ($($name,)* $last,) = self;
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)?);
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, 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))
}
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_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}

View File

@ -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);