commit
d239fcaa0e
|
@ -3,7 +3,7 @@
|
|||
name = "hlua"
|
||||
version = "0.1.0"
|
||||
authors = [ "pierre.krieger1708@gmail.com" ]
|
||||
description = "Zero-cast high-level wrapper for Lua"
|
||||
description = "Zero-cost high-level wrapper for Lua"
|
||||
repository = "https://github.com/tomaka/hlua"
|
||||
documentation = "http://tomaka.github.io/hlua/hlua/index.html"
|
||||
license = "MIT"
|
||||
|
|
|
@ -26,7 +26,9 @@ struct ReadData {
|
|||
triggered_error: Option<IoError>,
|
||||
}
|
||||
|
||||
extern fn reader(_: *mut ffi::lua_State, data_raw: *mut libc::c_void, size: *mut libc::size_t) -> *const libc::c_char {
|
||||
extern fn reader(_: *mut ffi::lua_State, data_raw: *mut libc::c_void, size: *mut libc::size_t)
|
||||
-> *const libc::c_char
|
||||
{
|
||||
let data: &mut ReadData = unsafe { mem::transmute(data_raw) };
|
||||
|
||||
if data.triggered_error.is_some() {
|
||||
|
@ -47,14 +49,16 @@ extern fn reader(_: *mut ffi::lua_State, data_raw: *mut libc::c_void, size: *mut
|
|||
}
|
||||
|
||||
impl<L> LuaFunction<L> where L: AsMutLua {
|
||||
/// Calls the `LuaFunction`.
|
||||
pub fn call<V>(&mut self) -> Result<V, LuaError>
|
||||
where V: for<'a> LuaRead<PushGuard<&'a mut L>> +
|
||||
for<'a> LuaRead<&'a mut L>
|
||||
{
|
||||
// calling pcall pops the parameters and pushes output
|
||||
let (pcall_return_value, pushed_value) = unsafe {
|
||||
ffi::lua_pushvalue(self.variable.as_mut_lua().0, -1); // lua_pcall pops the function, so we have to make a copy of it
|
||||
let pcall_return_value = ffi::lua_pcall(self.variable.as_mut_lua().0, 0, 1, 0); // TODO:
|
||||
// lua_pcall pops the function, so we have to make a copy of it
|
||||
ffi::lua_pushvalue(self.variable.as_mut_lua().0, -1);
|
||||
let pcall_return_value = ffi::lua_pcall(self.variable.as_mut_lua().0, 0, 1, 0); // TODO: arguments
|
||||
(pcall_return_value, PushGuard { lua: &mut self.variable, size: 1 })
|
||||
};
|
||||
|
||||
|
@ -81,6 +85,7 @@ impl<L> LuaFunction<L> where L: AsMutLua {
|
|||
panic!("Unknown error code returned by lua_pcall: {}", pcall_return_value)
|
||||
}
|
||||
|
||||
/// Builds a new `LuaFunction` from the code of a reader.
|
||||
pub fn load_from_reader<R>(mut lua: L, code: R) -> Result<LuaFunction<PushGuard<L>>, LuaError>
|
||||
where R: Read + 'static
|
||||
{
|
||||
|
@ -123,6 +128,7 @@ impl<L> LuaFunction<L> where L: AsMutLua {
|
|||
panic!("Unknown error while calling lua_load");
|
||||
}
|
||||
|
||||
/// Builds a new `LuaFunction` from a raw string.
|
||||
pub fn load(lua: L, code: &str) -> Result<LuaFunction<PushGuard<L>>, LuaError> {
|
||||
let code = code.into_bytes();
|
||||
let reader = Cursor::new(code);
|
||||
|
|
|
@ -13,7 +13,9 @@ use std::fmt::Debug;
|
|||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
///
|
||||
/// Wraps a type that implements `FnMut` so that it can be used by hlua.
|
||||
///
|
||||
/// This is only needed because of a limitation in Rust's inferrence system.
|
||||
pub fn function<F, P>(f: F) -> Function<F, P, <F as FnMut<P>>::Output> where F: FnMut<P> {
|
||||
Function {
|
||||
function: f,
|
||||
|
@ -21,6 +23,7 @@ pub fn function<F, P>(f: F) -> Function<F, P, <F as FnMut<P>>::Output> where F:
|
|||
}
|
||||
}
|
||||
|
||||
/// Opaque type containing a Rust function or closure.
|
||||
pub struct Function<F, P, R> {
|
||||
function: F,
|
||||
marker: PhantomData<(P, R)>,
|
||||
|
@ -72,8 +75,10 @@ trait AnyCallable {
|
|||
fn load_args_and_call(&mut self, lua: *mut ffi::lua_State) -> ::libc::c_int;
|
||||
}
|
||||
|
||||
// lua context used inside callbacks
|
||||
#[doc(hidden)]
|
||||
/// Opaque type that represents the Lua context when inside a callback.
|
||||
///
|
||||
/// Some types (like `Result`) can only be returned from a callback and not written inside a
|
||||
/// Lua variable. This type is here to enforce this restriction.
|
||||
pub struct InsideCallback {
|
||||
lua: LuaContext,
|
||||
}
|
||||
|
@ -123,7 +128,9 @@ impl<L, F, P, R> Push<L> for Function<F, P, R>
|
|||
}
|
||||
|
||||
impl<'a, T, E> Push<&'a mut InsideCallback> for Result<T, E>
|
||||
where T: Push<&'a mut InsideCallback> + for<'b> Push<&'b mut &'a mut InsideCallback>, E: Debug
|
||||
where T: Push<&'a mut InsideCallback> +
|
||||
for<'b> Push<&'b mut &'a mut InsideCallback>,
|
||||
E: Debug
|
||||
{
|
||||
fn push_to_lua(self, mut lua: &'a mut InsideCallback) -> PushGuard<&'a mut InsideCallback> {
|
||||
match self {
|
||||
|
@ -132,7 +139,7 @@ impl<'a, T, E> Push<&'a mut InsideCallback> for Result<T, E>
|
|||
let msg = format!("{:?}", val);
|
||||
msg.push_to_lua(&mut lua).forget();
|
||||
unsafe { ffi::lua_error(lua.as_mut_lua().0); }
|
||||
unreachable!()
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,13 +35,15 @@ pub struct Lua<'lua> {
|
|||
marker: PhantomData<&'lua ()>,
|
||||
}
|
||||
|
||||
///
|
||||
/// RAII guard for a value pushed on the stack.
|
||||
pub struct PushGuard<L> where L: AsMutLua {
|
||||
lua: L,
|
||||
size: i32,
|
||||
}
|
||||
|
||||
impl<L> PushGuard<L> where L: AsMutLua {
|
||||
/// Prevents the value from being poped when the `PushGuard` is destroyed, and returns the
|
||||
/// number of elements on the stack.
|
||||
fn forget(mut self) -> i32 {
|
||||
let size = self.size;
|
||||
self.size = 0;
|
||||
|
@ -49,17 +51,19 @@ impl<L> PushGuard<L> where L: AsMutLua {
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait for objects that have access to a Lua context.
|
||||
/// Trait for objects that have access to a Lua context. When using a context returned by a
|
||||
/// `AsLua`, you are not allowed to modify the stack.
|
||||
pub unsafe trait AsLua {
|
||||
fn as_lua(&self) -> LuaContext;
|
||||
}
|
||||
|
||||
/// Trait for objects that have access to a Lua context.
|
||||
/// Trait for objects that have access to a Lua context. You are allowed to modify the stack, but
|
||||
/// it must be in the same state as it was when you started.
|
||||
pub unsafe trait AsMutLua: AsLua {
|
||||
fn as_mut_lua(&mut self) -> LuaContext;
|
||||
}
|
||||
|
||||
/// Represents a raw Lua context.
|
||||
/// Opaque type that contains the raw Lua context.
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(raw_pointer_derive)]
|
||||
pub struct LuaContext(*mut ffi::lua_State);
|
||||
|
@ -113,24 +117,30 @@ unsafe impl<'a, L> AsMutLua for &'a mut L where L: AsMutLua {
|
|||
}
|
||||
}
|
||||
|
||||
/// Should be implemented by whatever type is pushable on the Lua stack.
|
||||
/// Types that can be given to a Lua context, for example with `lua.set()` or as a return value
|
||||
/// of a function.
|
||||
pub trait Push<L> where L: AsMutLua {
|
||||
/// Pushes the value on the top of the stack.
|
||||
/// Must return the number of elements pushed.
|
||||
///
|
||||
/// Must return a guard representing the elements that have been pushed.
|
||||
///
|
||||
/// You can implement this for any type you want by redirecting to call to
|
||||
/// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
|
||||
/// another implementation (for example `5.push_to_lua`) or by calling
|
||||
/// `userdata::push_userdata`.
|
||||
fn push_to_lua(self, lua: L) -> PushGuard<L>;
|
||||
}
|
||||
|
||||
/// Reads the data from Lua.
|
||||
/// Types that can be obtained from a Lua context.
|
||||
///
|
||||
/// Most types that implement `Push` also implement `LuaRead`, but this is not always the case
|
||||
/// (for example `&'static str` implements `Push` but not `LuaRead`).
|
||||
pub trait LuaRead<L>: Sized where L: AsLua {
|
||||
/// Reads the data from Lua.
|
||||
fn lua_read(lua: L) -> Option<Self> {
|
||||
LuaRead::lua_read_at_position(lua, -1)
|
||||
}
|
||||
|
||||
/// Reads the data from Lua.
|
||||
/// Reads the data from Lua at a given position.
|
||||
fn lua_read_at_position(lua: L, index: i32) -> Option<Self>;
|
||||
}
|
||||
|
||||
|
@ -195,10 +205,11 @@ impl<'lua> Lua<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Takes an existing lua_State and build a Lua object from it.
|
||||
/// Takes an existing `lua_State` and build a Lua object from it.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
|
||||
///
|
||||
/// * `close_at_the_end`: if true, lua_close will be called on the lua_State on the destructor
|
||||
pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
|
||||
Lua {
|
||||
lua: std::mem::transmute(lua),
|
||||
|
@ -215,22 +226,24 @@ impl<'lua> Lua<'lua> {
|
|||
|
||||
/// Executes some Lua code on the context.
|
||||
pub fn execute<'a, T>(&'a mut self, code: &str) -> Result<T, LuaError>
|
||||
where T: for<'g> LuaRead<&'g mut PushGuard<&'a mut Lua<'lua>>> +
|
||||
for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>
|
||||
where T: for<'g> LuaRead<&'g mut PushGuard<&'a mut Lua<'lua>>> +
|
||||
for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>
|
||||
{
|
||||
let mut f = try!(functions_read::LuaFunction::load(self, code));
|
||||
f.call()
|
||||
}
|
||||
|
||||
/// Executes some Lua code on the context.
|
||||
pub fn execute_from_reader<'a, T, R: Read + 'static>(&'a mut self, code: R) -> Result<T, LuaError>
|
||||
where T: for<'g> LuaRead<&'g mut PushGuard<&'a mut Lua<'lua>>> + for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>
|
||||
{
|
||||
pub fn execute_from_reader<'a, T, R>(&'a mut self, code: R) -> Result<T, LuaError>
|
||||
where T: for<'g> LuaRead<&'g mut PushGuard<&'a mut Lua<'lua>>> +
|
||||
for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>,
|
||||
R: Read + 'static
|
||||
{
|
||||
let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
|
||||
f.call()
|
||||
}
|
||||
|
||||
/// Reads the value of a global variable by copying it.
|
||||
/// Reads the value of a global variable.
|
||||
pub fn get<'l, V, I>(&'l mut self, index: I) -> Option<V>
|
||||
where I: Borrow<str>, V: LuaRead<&'l mut Lua<'lua>>
|
||||
{
|
||||
|
|
|
@ -9,7 +9,9 @@ use Push;
|
|||
use PushGuard;
|
||||
use LuaRead;
|
||||
|
||||
///
|
||||
/// Represents a table stored in the Lua context.
|
||||
///
|
||||
/// Loading this type mutably borrows the Lua context.
|
||||
pub struct LuaTable<L> {
|
||||
table: L,
|
||||
}
|
||||
|
@ -37,6 +39,7 @@ impl<L> LuaRead<L> for LuaTable<L> where L: AsMutLua {
|
|||
}
|
||||
}
|
||||
|
||||
/// Iterator that enumerates the content of a Lua table.
|
||||
// while the LuaTableIterator is active, the current key is constantly pushed over the table
|
||||
pub struct LuaTableIterator<'t, L: 't, K, V> {
|
||||
table: &'t mut LuaTable<L>,
|
||||
|
@ -57,6 +60,7 @@ unsafe impl<'t, L, K, V> AsMutLua for LuaTableIterator<'t, L, K, V> where L: AsM
|
|||
}
|
||||
|
||||
impl<L> LuaTable<L> where L: AsMutLua {
|
||||
/// Iterates over the elements inside the table.
|
||||
pub fn iter<K, V>(&mut self) -> LuaTableIterator<L, K, V> {
|
||||
unsafe { ffi::lua_pushnil(self.table.as_mut_lua().0) };
|
||||
|
||||
|
@ -67,7 +71,11 @@ impl<L> LuaTable<L> where L: AsMutLua {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R> where R: for<'b> LuaRead<&'b mut &'a mut LuaTable<L>>, I: for<'b> Push<&'b mut &'a mut LuaTable<L>> {
|
||||
/// Loads a value in the table given its index.
|
||||
pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R>
|
||||
where R: for<'b> LuaRead<&'b mut &'a mut LuaTable<L>>,
|
||||
I: for<'b> Push<&'b mut &'a mut LuaTable<L>>
|
||||
{
|
||||
let mut me = self;
|
||||
index.push_to_lua(&mut me).forget();
|
||||
unsafe { ffi::lua_gettable(me.as_mut_lua().0, -2); }
|
||||
|
@ -76,6 +84,7 @@ impl<L> LuaTable<L> where L: AsMutLua {
|
|||
value
|
||||
}
|
||||
|
||||
/// Inserts or modifies an elements of the table.
|
||||
pub fn set<'s, I, V>(&'s mut self, index: I, value: V)
|
||||
where I: for<'a> Push<&'a mut &'s mut LuaTable<L>>,
|
||||
V: for<'a> Push<&'a mut &'s mut LuaTable<L>>
|
||||
|
@ -86,7 +95,7 @@ impl<L> LuaTable<L> where L: AsMutLua {
|
|||
unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }
|
||||
}
|
||||
|
||||
// Obtains or create the metatable of the table
|
||||
/// Obtains or create the metatable of the table.
|
||||
pub fn get_or_create_metatable(mut self) -> LuaTable<PushGuard<L>> {
|
||||
let result = unsafe { ffi::lua_getmetatable(self.table.as_mut_lua().0, -1) };
|
||||
|
||||
|
|
|
@ -66,13 +66,18 @@ impl<'a, L, T> Push<L> for &'a [T] where L: AsMutLua, T: Clone + for<'b> Push<&'
|
|||
}
|
||||
}
|
||||
|
||||
impl<L, K, V> Push<L> for HashMap<K, V> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash, V: for<'a, 'b> Push<&'a mut &'b mut L> {
|
||||
impl<L, K, V> Push<L> for HashMap<K, V> where L: AsMutLua,
|
||||
K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash,
|
||||
V: for<'a, 'b> Push<&'a mut &'b mut L>
|
||||
{
|
||||
fn push_to_lua(self, lua: L) -> PushGuard<L> {
|
||||
push_rec_iter(lua, self.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, K> Push<L> for HashSet<K> where L: AsMutLua, K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash {
|
||||
impl<L, K> Push<L> for HashSet<K> where L: AsMutLua,
|
||||
K: for<'a, 'b> Push<&'a mut &'b mut L> + Eq + Hash
|
||||
{
|
||||
fn push_to_lua(self, lua: L) -> PushGuard<L> {
|
||||
use std::iter;
|
||||
push_rec_iter(lua, self.into_iter().zip(iter::repeat(true)))
|
||||
|
|
|
@ -22,8 +22,8 @@ macro_rules! tuple_impl {
|
|||
|
||||
($first:ident, $($other:ident),+) => (
|
||||
#[allow(non_snake_case)]
|
||||
impl<LU, $first: for<'a> Push<&'a mut LU>, $($other: for<'a> Push<&'a mut LU>),+> Push<LU> for ($first, $($other),+)
|
||||
where LU: AsMutLua
|
||||
impl<LU, $first: for<'a> Push<&'a mut LU>, $($other: for<'a> Push<&'a mut LU>),+>
|
||||
Push<LU> for ($first, $($other),+) where LU: AsMutLua
|
||||
{
|
||||
fn push_to_lua(self, mut lua: LU) -> PushGuard<LU> {
|
||||
match self {
|
||||
|
@ -43,7 +43,9 @@ macro_rules! tuple_impl {
|
|||
// TODO: what if T or U are also tuples? indices won't match
|
||||
#[allow(unused_assignments)]
|
||||
#[allow(non_snake_case)]
|
||||
impl<LU, $first: for<'a> LuaRead<&'a mut LU>, $($other: for<'a> LuaRead<&'a mut LU>),+> LuaRead<LU> for ($first, $($other),+) where LU: AsLua {
|
||||
impl<LU, $first: for<'a> LuaRead<&'a mut LU>, $($other: for<'a> LuaRead<&'a mut LU>),+>
|
||||
LuaRead<LU> for ($first, $($other),+) where LU: AsLua
|
||||
{
|
||||
fn lua_read_at_position(mut lua: LU, index: i32) -> Option<($first, $($other),+)> {
|
||||
let mut i = index;
|
||||
|
||||
|
|
|
@ -33,15 +33,17 @@ fn destructor_impl<T>(lua: *mut ffi::lua_State) -> libc::c_int {
|
|||
/// Pushes an object as a user data.
|
||||
///
|
||||
/// In Lua, a user data is anything that is not recognized by Lua. When the script attempts to
|
||||
/// copy a user data, instead only a reference to the data is copied.
|
||||
/// copy a user data, instead only a reference to the data is copied.
|
||||
///
|
||||
/// The way a Lua script can use the user data depends on the content of the **metatable**, which
|
||||
/// is a Lua table linked to the object.
|
||||
/// is a Lua table linked to the object.
|
||||
///
|
||||
/// [See this link for more infos.](http://www.lua.org/manual/5.2/manual.html#2.4)
|
||||
///
|
||||
/// # Arguments
|
||||
/// * metatable: Function that fills the metatable of the object.
|
||||
///
|
||||
/// - `metatable`: Function that fills the metatable of the object.
|
||||
///
|
||||
pub fn push_userdata<L, T, F>(data: T, mut lua: L, mut metatable: F) -> PushGuard<L>
|
||||
where F: FnMut(LuaTable<&mut PushGuard<&mut L>>), L: AsMutLua,
|
||||
T: Send + 'static
|
||||
|
@ -91,6 +93,7 @@ pub fn push_userdata<L, T, F>(data: T, mut lua: L, mut metatable: F) -> PushGuar
|
|||
PushGuard { lua: lua, size: 1 }
|
||||
}
|
||||
|
||||
///
|
||||
pub fn read_userdata<T, L>(mut lua: L, index: i32) -> Option<UserdataOnStack<T, L>>
|
||||
where L: AsMutLua, T: 'static
|
||||
{
|
||||
|
@ -122,6 +125,7 @@ pub fn read_userdata<T, L>(mut lua: L, index: i32) -> Option<UserdataOnStack<T,
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a user data located inside the Lua context.
|
||||
pub struct UserdataOnStack<T, L> {
|
||||
variable: L,
|
||||
marker: PhantomData<T>,
|
||||
|
|
Loading…
Reference in New Issue