expose methods to operate on PushGuards from outside this library

This is most useful when using a library to poke at the Rust state.

The most important methods made public are `new` to create a new
`PushGuard`, and `forget` to not run this `PushGuard`'s destructor.
They're both unsafe because their misuse can easily cause crashes.

Also expose a `size` method to access the number of elements this
`PushGuard` is managing, and provide an internal-only safe version of
`forget` under the assumption that consumers within this crate know what
they're doing.
master
Siddharth Agarwal 2017-08-27 16:04:12 -07:00
parent 42992f1448
commit e8bcc05367
6 changed files with 47 additions and 18 deletions

View File

@ -64,7 +64,7 @@ impl<'lua, L> Push<L> for AnyLuaValue
// We also need to destroy and recreate the push guard, otherwise the type parameter
// doesn't match.
let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget();
let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();
Ok(PushGuard {
lua: lua,
@ -149,7 +149,7 @@ impl<'lua, L> Push<L> for AnyHashableLuaValue
// We also need to destroy and recreate the push guard, otherwise the type parameter
// doesn't match.
let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget();
let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();
Ok(PushGuard {
lua: lua,

View File

@ -69,7 +69,7 @@ impl_function!(function10, A, B, C, D, E, F, G, H, I, J);
/// ```
/// use hlua::Lua;
/// let mut lua = Lua::new();
///
///
/// lua.set("foo", hlua::function1(move |a: i32| -> i32 {
/// a * 5
/// }));
@ -106,7 +106,7 @@ impl_function!(function10, A, B, C, D, E, F, G, H, I, J);
/// ```
/// use hlua::Lua;
/// let mut lua = Lua::new();
///
///
/// lua.set("values", hlua::function0(move || -> (i32, i32, i32) {
/// (12, 24, 48)
/// }));
@ -130,7 +130,7 @@ impl_function!(function10, A, B, C, D, E, F, G, H, I, J);
/// use hlua::Lua;
/// let mut lua = Lua::new();
/// lua.openlibs();
///
///
/// lua.set("err", hlua::function0(move || -> Result<i32, &'static str> {
/// Err("something wrong happened")
/// }));
@ -287,7 +287,7 @@ macro_rules! impl_function_ext {
// without going through the RFC process.
{
match "__gc".push_to_lua(&mut lua) {
Ok(p) => p.forget(),
Ok(p) => p.forget_internal(),
Err(_) => unreachable!(),
};
@ -399,7 +399,7 @@ extern "C" fn wrapper<T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
Err(_) => {
let err_msg = format!("wrong parameter types for callback function");
match err_msg.push_to_lua(&mut tmp_lua) {
Ok(p) => p.forget(),
Ok(p) => p.forget_internal(),
Err(_) => unreachable!(),
};
unsafe {
@ -414,7 +414,7 @@ extern "C" fn wrapper<T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
// pushing back the result of the function on the stack
let nb = match ret_value.push_to_lua(&mut tmp_lua) {
Ok(p) => p.forget(),
Ok(p) => p.forget_internal(),
Err(_) => panic!(), // TODO: wrong
};
nb as libc::c_int

View File

@ -170,16 +170,45 @@ pub struct PushGuard<L> {
impl<'lua, L> PushGuard<L>
where L: AsMutLua<'lua>
{
/// Creates a new `PushGuard` from this Lua context representing `size` items on the stack.
/// When this `PushGuard` is destroyed, `size` items will be popped.
///
/// This is unsafe because the Lua stack can be corrupted if this is misused.
#[inline]
pub unsafe fn new(mut lua: L, size: i32) -> Self {
let raw_lua = lua.as_mut_lua();
PushGuard {
lua,
size,
raw_lua,
}
}
#[inline]
fn assert_one_and_forget(self) -> i32 {
assert_eq!(self.size, 1);
self.forget()
self.forget_internal()
}
/// Prevents the value from being poped when the `PushGuard` is destroyed, and returns the
/// number of elements on the stack.
/// Returns the number of elements managed by this `PushGuard`.
#[inline]
fn forget(mut self) -> i32 {
pub fn size(&self) -> i32 {
self.size
}
/// Prevents the value from being popped when the `PushGuard` is destroyed, and returns the
/// number of elements on the Lua stack.
///
/// This is unsafe because the Lua stack can be corrupted if this is misused.
#[inline]
pub unsafe fn forget(self) -> i32 {
self.forget_internal()
}
/// Internal crate-only version of `forget`. It is generally assumed that code within this
/// crate that calls this method knows what it is doing.
#[inline]
fn forget_internal(mut self) -> i32 {
let size = self.size;
self.size = 0;
size

View File

@ -264,7 +264,7 @@ impl<'lua, L> LuaFunction<L>
// 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 num_pushed = match args.push_to_lua(self) {
Ok(g) => g.forget(),
Ok(g) => g.forget_internal(),
Err((err, _)) => return Err(LuaFunctionCallError::PushError(err)),
};
let pcall_return_value = ffi::lua_pcall(self.variable.as_mut_lua().0, num_pushed, 1, 0); // TODO: num ret values

View File

@ -23,7 +23,7 @@ fn push_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>,
for (elem, index) in iterator.zip((1..)) {
let size = match elem.push_to_lua(&mut lua) {
Ok(pushed) => pushed.forget(),
Ok(pushed) => pushed.forget_internal(),
Err((_err, _lua)) => panic!(), // TODO: wrong return Err((err, lua)), // FIXME: destroy the temporary table
};
@ -32,7 +32,7 @@ fn push_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<L>,
1 => {
let index = index as u32;
match index.push_to_lua(&mut lua) {
Ok(pushed) => pushed.forget(),
Ok(pushed) => pushed.forget_internal(),
Err(_) => unreachable!(),
};
unsafe { ffi::lua_insert(lua.as_mut_lua().0, -2) }
@ -64,7 +64,7 @@ fn push_rec_iter<'lua, L, V, I, E>(mut lua: L, iterator: I) -> Result<PushGuard<
for elem in iterator {
let size = match elem.push_to_lua(&mut lua) {
Ok(pushed) => pushed.forget(),
Ok(pushed) => pushed.forget_internal(),
Err((_err, _lua)) => panic!(), // TODO: wrong return Err((err, lua)), // FIXME: destroy the temporary table
};

View File

@ -45,7 +45,7 @@ macro_rules! tuple_impl {
let mut total = 0;
let first_err = match $first.push_to_lua(&mut lua) {
Ok(pushed) => { total += pushed.forget(); None },
Ok(pushed) => { total += pushed.forget_internal(); None },
Err((err, _)) => Some(err),
};
@ -55,7 +55,7 @@ macro_rules! tuple_impl {
let rest = ($($other,)+);
let other_err = match rest.push_to_lua(&mut lua) {
Ok(pushed) => { total += pushed.forget(); None },
Ok(pushed) => { total += pushed.forget_internal(); None },
Err((err, _)) => Some(err),
};