Merge pull request #32 from tomaka/docs-and-style

Docs and style
master
tomaka 2015-02-27 13:40:22 +01:00
commit d239fcaa0e
8 changed files with 83 additions and 37 deletions

View File

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

View File

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

View File

@ -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!();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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