Fix references to hlists in documentation, improve? Variadic usability

Also rename to/from/pack/unpack to pack/unpack/pack_multi/unpack_multi, I don't
know if this makes their usage clearer, and it IS a bit confusing that I'm
changing the meaning of the words 'pack' and 'unpack'
This commit is contained in:
kyren 2017-08-01 13:55:08 -04:00
parent c1abc18066
commit 48bf35dc5b
4 changed files with 76 additions and 43 deletions

View File

@ -77,29 +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::<_, ()>(("hello", "again", "from", "rust"))?;
// You can bind rust functions to lua as well
// 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. 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.
// 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(|_, strings: Variadic<String>| {
// (This is quadratic!, it's just an example!)
Ok(strings.0.iter().fold("".to_owned(), |a, b| a + b))
Ok(strings.iter().fold("".to_owned(), |a, b| a + b))
});
globals.set("join", join)?;
@ -139,9 +138,7 @@ fn examples() -> Result<()> {
}
}
let vec2_constructor = lua.create_function(|_, (x, y): (f32, f32)| {
Ok(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

@ -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;
@ -1518,7 +1516,7 @@ impl Lua {
/// # }
/// ```
///
/// Use the `hlist_macro` crate to use multiple arguments:
/// Use tuples to accept multiple arguments:
///
/// ```
/// # extern crate rlua;
@ -1674,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,3 +1,5 @@
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;
use std::result::Result as StdResult;
use error::*;
@ -49,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>> {
@ -128,7 +166,7 @@ macro_rules! push_reverse {
($multi_value:expr,) => ();
}
impl_tuple! { }
impl_tuple!{}
impl_tuple! { A }
impl_tuple! { A B }
impl_tuple! { A B C }

View File

@ -220,9 +220,7 @@ fn test_rust_function() {
).unwrap();
let lua_function = globals.get::<_, Function>("lua_function").unwrap();
let rust_function = lua.create_function(|_, _: ()| {
Ok("hello")
});
let rust_function = lua.create_function(|_, _: ()| Ok("hello"));
globals.set("rust_function", rust_function).unwrap();
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
@ -303,13 +301,14 @@ fn test_metamethods() {
methods.add_meta_function(MetaMethod::Sub, |_, (lhs, rhs): (MyUserData, MyUserData)| {
Ok(MyUserData(lhs.0 - rhs.0))
});
methods.add_meta_method(MetaMethod::Index, |_, data, index: LuaString| {
if index.to_str()? == "inner" {
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())
}
});
},
);
}
}
@ -382,9 +381,9 @@ fn test_lua_multi() {
assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar");
let (a, b) = mreturn.call::<_, (u64, u64)>(()).unwrap();
assert_eq!((a, b), (1, 2));
let (a, b, Variadic(v)) = mreturn.call::<_, (u64, u64, Variadic<u64>)>(()).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]