2017-05-21 19:50:59 -04:00
|
|
|
use std::fmt;
|
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
use std::iter::FromIterator;
|
|
|
|
use std::cell::{RefCell, Ref, RefMut};
|
|
|
|
use std::ptr;
|
|
|
|
use std::mem;
|
|
|
|
use std::ffi::{CStr, CString};
|
|
|
|
use std::any::TypeId;
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
use std::collections::{HashMap, VecDeque};
|
|
|
|
use std::collections::hash_map::Entry as HashMapEntry;
|
|
|
|
use std::os::raw::{c_char, c_int, c_void};
|
|
|
|
|
|
|
|
use ffi;
|
|
|
|
use error::*;
|
|
|
|
use util::*;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A dynamically typed Lua value.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum LuaValue<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The Lua value `nil`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Nil,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The Lua value `true` or `false`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Boolean(bool),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A "light userdata" object, equivalent to a raw pointer.
|
2017-05-25 00:43:35 -04:00
|
|
|
LightUserData(LightUserData),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// An integer number.
|
|
|
|
///
|
|
|
|
/// Any Lua number convertible to a `LuaInteger` will be represented as this variant.
|
2017-05-21 19:50:59 -04:00
|
|
|
Integer(LuaInteger),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A floating point number.
|
2017-05-21 19:50:59 -04:00
|
|
|
Number(LuaNumber),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// An interned string, managed by Lua.
|
|
|
|
///
|
|
|
|
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
|
2017-05-21 19:50:59 -04:00
|
|
|
String(LuaString<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua table.
|
2017-05-21 19:50:59 -04:00
|
|
|
Table(LuaTable<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua function (or closure).
|
2017-05-21 19:50:59 -04:00
|
|
|
Function(LuaFunction<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a "full" userdata object.
|
2017-05-21 19:50:59 -04:00
|
|
|
UserData(LuaUserData<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua thread (or coroutine).
|
2017-05-24 23:13:58 -04:00
|
|
|
Thread(LuaThread<'lua>),
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
pub use self::LuaValue::Nil as LuaNil;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible to `LuaValue`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait ToLua<'a> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn to_lua(self, lua: &'a Lua) -> LuaResult<LuaValue<'a>>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible from `LuaValue`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait FromLua<'a>: Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn from_lua(lua_value: LuaValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Multiple Lua values used for both argument passing and also for multiple return values.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct LuaMultiValue<'lua>(VecDeque<LuaValue<'lua>>);
|
|
|
|
|
|
|
|
impl<'lua> LuaMultiValue<'lua> {
|
|
|
|
pub fn new() -> LuaMultiValue<'lua> {
|
|
|
|
LuaMultiValue(VecDeque::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> FromIterator<LuaValue<'lua>> for LuaMultiValue<'lua> {
|
|
|
|
fn from_iter<I: IntoIterator<Item = LuaValue<'lua>>>(iter: I) -> Self {
|
|
|
|
LuaMultiValue(VecDeque::from_iter(iter))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> IntoIterator for LuaMultiValue<'lua> {
|
|
|
|
type Item = LuaValue<'lua>;
|
|
|
|
type IntoIter = <VecDeque<LuaValue<'lua>> as IntoIterator>::IntoIter;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
self.0.into_iter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Deref for LuaMultiValue<'lua> {
|
|
|
|
type Target = VecDeque<LuaValue<'lua>>;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> DerefMut for LuaMultiValue<'lua> {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible to any number of Lua values.
|
|
|
|
///
|
|
|
|
/// This is a generalization of `ToLua`, allowing any number of resulting Lua values instead of just
|
|
|
|
/// one. Any type that implements `ToLua` will automatically implement this trait.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait ToLuaMulti<'a> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn to_lua_multi(self, lua: &'a Lua) -> LuaResult<LuaMultiValue<'a>>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types that can be created from an arbitrary number of Lua values.
|
|
|
|
///
|
|
|
|
/// This is a generalization of `FromLua`, allowing an arbitrary number of Lua values to participate
|
|
|
|
/// in the conversion. Any type that implements `FromLua` will automatically implement this trait.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait FromLuaMulti<'a>: Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
|
|
|
///
|
|
|
|
/// In case `values` contains more values than needed to perform the conversion, the excess
|
|
|
|
/// values should be ignored. This reflects the semantics of Lua when calling a function or
|
|
|
|
/// assigning values. Of course, if not enough values are given, an error should be returned.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn from_lua_multi(values: LuaMultiValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
|
|
|
}
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
type LuaCallback = Box<
|
|
|
|
for<'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>,
|
|
|
|
>;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
struct LuaRef<'lua> {
|
|
|
|
lua: &'lua Lua,
|
|
|
|
registry_id: c_int,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> fmt::Debug for LuaRef<'lua> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "LuaRef({})", self.registry_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Clone for LuaRef<'lua> {
|
|
|
|
fn clone(&self) -> Self {
|
2017-05-25 00:43:35 -04:00
|
|
|
unsafe {
|
|
|
|
self.lua.push_ref(self.lua.state, self);
|
|
|
|
self.lua.pop_ref(self.lua.state)
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Drop for LuaRef<'lua> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
ffi::luaL_unref(self.lua.state, ffi::LUA_REGISTRYINDEX, self.registry_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Type of Lua integer numbers.
|
2017-05-25 00:43:35 -04:00
|
|
|
pub type LuaInteger = ffi::lua_Integer;
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Type of Lua floating point numbers.
|
2017-05-25 00:43:35 -04:00
|
|
|
pub type LuaNumber = ffi::lua_Number;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A "light" userdata value. Equivalent to an unmanaged raw pointer.
|
2017-05-25 00:43:35 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
|
|
pub struct LightUserData(pub *mut c_void);
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua string.
|
|
|
|
///
|
|
|
|
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaString<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaString<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Get a `&str` slice if the Lua string is valid UTF-8.
|
2017-06-18 08:48:45 -04:00
|
|
|
pub fn to_str(&self) -> LuaResult<&str> {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1)?;
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING);
|
|
|
|
let s = CStr::from_ptr(ffi::lua_tostring(lua.state, -1)).to_str()?;
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(s)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua table.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaTable<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaTable<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Sets a key-value pair in the table.
|
|
|
|
///
|
|
|
|
/// If the value is `nil`, this will effectively remove the pair.
|
|
|
|
///
|
|
|
|
/// This might invoke the `__newindex` metamethod. Use the `raw_set` method if that is not
|
|
|
|
/// desired.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> {
|
|
|
|
let lua = self.0.lua;
|
2017-06-05 00:41:48 -04:00
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
let value = value.to_lua(lua)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2017-06-05 00:41:48 -04:00
|
|
|
error_guard(lua.state, 0, 0, |state| {
|
|
|
|
check_stack(state, 3)?;
|
|
|
|
lua.push_ref(state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(state, key);
|
|
|
|
lua.push_value(state, value);
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_settable(state, -3);
|
2017-06-05 00:03:39 -04:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the value associated to `key` from the table.
|
|
|
|
///
|
|
|
|
/// If no value is associated to `key`, returns the `nil` value.
|
|
|
|
///
|
|
|
|
/// This might invoke the `__index` metamethod. Use the `raw_get` method if that is not desired.
|
2017-06-05 00:41:48 -04:00
|
|
|
pub fn get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> LuaResult<V> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
unsafe {
|
|
|
|
let res = error_guard(lua.state, 0, 0, |state| {
|
|
|
|
check_stack(state, 2)?;
|
|
|
|
lua.push_ref(state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(state, key.to_lua(lua)?);
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_gettable(state, -2);
|
2017-06-19 02:57:03 -04:00
|
|
|
let res = lua.pop_value(state);
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
Ok(res)
|
|
|
|
})?;
|
|
|
|
V::from_lua(res, lua)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Checks whether the table contains a non-nil value for `key`.
|
2017-06-18 08:39:18 -04:00
|
|
|
pub fn contains_key<K: ToLua<'lua>>(&self, key: K) -> LuaResult<bool> {
|
2017-06-11 01:12:25 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
unsafe {
|
|
|
|
error_guard(lua.state, 0, 0, |state| {
|
|
|
|
check_stack(state, 2)?;
|
|
|
|
lua.push_ref(state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(state, key);
|
2017-06-11 01:12:25 -04:00
|
|
|
ffi::lua_gettable(state, -2);
|
|
|
|
let has = ffi::lua_isnil(state, -1) == 0;
|
|
|
|
ffi::lua_pop(state, 2);
|
|
|
|
Ok(has)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Sets a key-value pair without invoking metamethods.
|
2017-06-05 00:03:39 -04:00
|
|
|
pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 3)?;
|
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
|
|
|
lua.push_value(lua.state, value.to_lua(lua)?);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(lua.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the value associated to `key` without invoking metamethods.
|
2017-06-05 00:41:48 -04:00
|
|
|
pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> LuaResult<V> {
|
2017-06-05 00:03:39 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 2)?;
|
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_gettable(lua.state, -2);
|
2017-06-19 02:57:03 -04:00
|
|
|
let res = V::from_lua(lua.pop_value(lua.state), lua)?;
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns the result of the Lua `#` operator.
|
|
|
|
///
|
2017-06-18 18:11:55 -04:00
|
|
|
/// This might invoke the `__len` metamethod. Use the `raw_len` method if
|
|
|
|
/// that is not desired.
|
2017-06-18 08:36:30 -04:00
|
|
|
pub fn len(&self) -> LuaResult<LuaInteger> {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
2017-06-05 00:41:48 -04:00
|
|
|
error_guard(lua.state, 0, 0, |state| {
|
|
|
|
check_stack(state, 1)?;
|
|
|
|
lua.push_ref(state, &self.0);
|
|
|
|
Ok(ffi::luaL_len(state, -1))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns the result of the Lua `#` operator, without invoking the
|
|
|
|
/// `__len` metamethod.
|
2017-06-18 08:36:30 -04:00
|
|
|
pub fn raw_len(&self) -> LuaResult<LuaInteger> {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1)?;
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-05 00:41:48 -04:00
|
|
|
let len = ffi::lua_rawlen(lua.state, -1);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(len as LuaInteger)
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// Consume this table and return an iterator over the pairs of the table,
|
2017-06-19 03:08:50 -04:00
|
|
|
/// works like the Lua 'pairs' function.
|
2017-06-19 02:57:03 -04:00
|
|
|
pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> LuaTablePairs<'lua, K, V> {
|
|
|
|
let next_key = Some(LuaRef {
|
|
|
|
lua: self.0.lua,
|
|
|
|
registry_id: ffi::LUA_REFNIL,
|
|
|
|
});
|
|
|
|
|
|
|
|
LuaTablePairs {
|
|
|
|
table: self.0,
|
|
|
|
next_key,
|
|
|
|
_phantom: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// Consume this table and return an iterator over the values of this table,
|
|
|
|
/// which should be a sequence. Works like the Lua 'ipairs' function, but
|
|
|
|
/// doesn't return the indexes, only the values in order.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub fn sequence_values<V: FromLua<'lua>>(self) -> LuaTableSequence<'lua, V> {
|
|
|
|
LuaTableSequence {
|
2017-06-19 02:57:03 -04:00
|
|
|
table: self.0,
|
|
|
|
index: Some(1),
|
|
|
|
_phantom: PhantomData,
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// An iterator over the pairs of a Lua table.
|
|
|
|
///
|
2017-06-19 03:08:50 -04:00
|
|
|
/// Should behave exactly like the lua 'pairs' function. Holds an internal
|
2017-06-19 02:57:03 -04:00
|
|
|
/// reference to the table.
|
|
|
|
pub struct LuaTablePairs<'lua, K, V> {
|
|
|
|
table: LuaRef<'lua>,
|
|
|
|
next_key: Option<LuaRef<'lua>>,
|
|
|
|
_phantom: PhantomData<(K, V)>,
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
impl<'lua, K, V> Iterator for LuaTablePairs<'lua, K, V>
|
|
|
|
where
|
|
|
|
K: FromLua<'lua>,
|
|
|
|
V: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
type Item = LuaResult<(K, V)>;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if let Some(next_key) = self.next_key.take() {
|
|
|
|
let lua = self.table.lua;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe {
|
|
|
|
if let Err(e) = check_stack(lua.state, 4) {
|
|
|
|
return Some(Err(e));
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_ref(lua.state, &self.table);
|
|
|
|
lua.push_ref(lua.state, &next_key);
|
|
|
|
|
|
|
|
match error_guard(lua.state, 2, 0, |state| if ffi::lua_next(state, -2) != 0 {
|
|
|
|
ffi::lua_pushvalue(state, -2);
|
|
|
|
let key = lua.pop_value(state);
|
|
|
|
let value = lua.pop_value(state);
|
|
|
|
let next_key = lua.pop_ref(lua.state);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(Some((key, value, next_key)))
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(None)
|
|
|
|
}) {
|
|
|
|
Ok(Some((key, value, next_key))) => {
|
|
|
|
self.next_key = Some(next_key);
|
|
|
|
Some((|| {
|
|
|
|
let key = K::from_lua(key, lua)?;
|
|
|
|
let value = V::from_lua(value, lua)?;
|
|
|
|
Ok((key, value))
|
|
|
|
})())
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
Ok(None) => None,
|
|
|
|
Err(e) => Some(Err(e)),
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-26 23:49:12 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// An iterator over the sequence part of a Lua table.
|
|
|
|
///
|
|
|
|
/// Should behave similarly to the lua 'ipairs" function, except only produces
|
|
|
|
/// the values, not the indexes. Holds an internal reference to the table.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub struct LuaTableSequence<'lua, V> {
|
2017-06-19 02:57:03 -04:00
|
|
|
table: LuaRef<'lua>,
|
|
|
|
index: Option<LuaInteger>,
|
|
|
|
_phantom: PhantomData<V>,
|
|
|
|
}
|
|
|
|
|
2017-06-20 19:04:25 -04:00
|
|
|
impl<'lua, V> Iterator for LuaTableSequence<'lua, V>
|
2017-06-19 02:57:03 -04:00
|
|
|
where
|
|
|
|
V: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
type Item = LuaResult<V>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if let Some(index) = self.index.take() {
|
|
|
|
let lua = self.table.lua;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
if let Err(e) = check_stack(lua.state, 2) {
|
|
|
|
return Some(Err(e));
|
|
|
|
}
|
2017-05-26 23:49:12 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_ref(lua.state, &self.table);
|
|
|
|
match error_guard(
|
|
|
|
lua.state,
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
|state| if ffi::lua_geti(state, -1, index) != ffi::LUA_TNIL {
|
|
|
|
let value = lua.pop_value(state);
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
Ok(Some(value))
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(state, 2);
|
|
|
|
Ok(None)
|
|
|
|
},
|
|
|
|
) {
|
|
|
|
Ok(Some(r)) => {
|
|
|
|
self.index = Some(index + 1);
|
|
|
|
Some(V::from_lua(r, lua))
|
|
|
|
}
|
|
|
|
Ok(None) => None,
|
|
|
|
Err(e) => Some(Err(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2017-05-26 23:49:12 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua function.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaFunction<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaFunction<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Calls the function, passing `args` as function arguments.
|
|
|
|
///
|
|
|
|
/// The function's return values are converted to the generic type `R`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> LuaResult<R> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
2017-06-05 00:03:39 -04:00
|
|
|
check_stack(lua.state, nargs + 3)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let stack_start = ffi::lua_gettop(lua.state);
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, arg);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
lua.state,
|
|
|
|
pcall_with_traceback(lua.state, nargs, ffi::LUA_MULTRET),
|
|
|
|
)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
let nresults = ffi::lua_gettop(lua.state) - stack_start;
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(lua.pop_value(lua.state));
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
R::from_lua_multi(results, lua)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns a function that, when called with no arguments, calls `self`, passing `args` as
|
|
|
|
/// arguments.
|
|
|
|
///
|
|
|
|
/// This is equivalent to this Lua code:
|
|
|
|
///
|
|
|
|
/// ```notrust
|
|
|
|
/// function bind(f, ...)
|
|
|
|
/// return function() f(...) end
|
|
|
|
/// end
|
|
|
|
/// ```
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn bind<A: ToLuaMulti<'lua>>(&self, args: A) -> LuaResult<LuaFunction<'lua>> {
|
|
|
|
unsafe extern "C" fn bind_call_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
let nargs = ffi::lua_gettop(state);
|
|
|
|
|
|
|
|
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(2)) as c_int;
|
|
|
|
check_stack(state, nbinds + 1).expect("not enough space to handle bound arguments");
|
|
|
|
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
|
|
|
ffi::lua_insert(state, 1);
|
|
|
|
|
|
|
|
// TODO: This is quadratic
|
|
|
|
for i in 0..nbinds {
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 3));
|
|
|
|
ffi::lua_insert(state, i + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
ffi::lua_call(state, nargs + nbinds, ffi::LUA_MULTRET);
|
|
|
|
ffi::lua_gettop(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
|
|
|
|
|
|
|
check_stack(lua.state, nargs + 2)?;
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
|
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, arg);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::lua_pushcclosure(lua.state, bind_call_impl, nargs + 2);
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaFunction(lua.pop_ref(lua.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Status of a Lua thread (or coroutine).
|
|
|
|
///
|
|
|
|
/// A `LuaThread` is `Active` before the coroutine function finishes, Dead after
|
2017-06-15 16:27:39 -04:00
|
|
|
/// it finishes, and in Error state if error has been called inside the
|
|
|
|
/// coroutine.
|
2017-05-24 23:13:58 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
|
|
pub enum LuaThreadStatus {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread has finished executing.
|
2017-05-24 23:13:58 -04:00
|
|
|
Dead,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread is currently running or suspended because it has called `coroutine.yield`.
|
2017-05-24 23:13:58 -04:00
|
|
|
Active,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread has thrown an error during execution.
|
2017-05-24 23:13:58 -04:00
|
|
|
Error,
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua thread (or coroutine).
|
2017-05-24 23:13:58 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaThread<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaThread<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Resumes execution of this thread.
|
|
|
|
///
|
|
|
|
/// Equivalent to `coroutine.resume`.
|
|
|
|
///
|
|
|
|
/// Passes `args` as arguments to the thread. If the coroutine has called `coroutine.yield`, it
|
|
|
|
/// will return these arguments. Otherwise, the coroutine wasn't yet started, so the arguments
|
|
|
|
/// are passed to its main function.
|
|
|
|
///
|
|
|
|
/// If the thread is no longer in `Active` state (meaning it has finished execution or
|
2017-06-17 23:50:40 -04:00
|
|
|
/// encountered an error), this will return Err(CoroutineInactive),
|
|
|
|
/// otherwise will return Ok as follows:
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
|
|
|
/// If the thread calls `coroutine.yield`, returns the values passed to `yield`. If the thread
|
|
|
|
/// `return`s values from its main function, returns those.
|
2017-06-21 18:27:26 -04:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # extern crate rlua;
|
|
|
|
/// # use rlua::*;
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// let lua = Lua::new();
|
|
|
|
/// let thread: LuaThread = lua.eval(r#"
|
|
|
|
/// coroutine.create(function(arg)
|
|
|
|
/// assert(arg == 42)
|
|
|
|
/// local yieldarg = coroutine.yield(123)
|
|
|
|
/// assert(yieldarg == 43)
|
|
|
|
/// return 987
|
|
|
|
/// end)
|
|
|
|
/// "#).unwrap();
|
|
|
|
///
|
|
|
|
/// assert_eq!(thread.resume::<_, u32>(42).unwrap(), 123);
|
|
|
|
/// assert_eq!(thread.resume::<_, u32>(43).unwrap(), 987);
|
|
|
|
///
|
|
|
|
/// // The coroutine has now returned, so `resume` will fail
|
|
|
|
/// match thread.resume::<_, u32>(()) {
|
|
|
|
/// Err(LuaError(LuaErrorKind::CoroutineInactive, _)) => {},
|
|
|
|
/// unexpected => panic!("unexpected result {:?}", unexpected),
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2017-06-17 23:50:40 -04:00
|
|
|
pub fn resume<A, R>(&self, args: A) -> LuaResult<R>
|
|
|
|
where
|
|
|
|
A: ToLuaMulti<'lua>,
|
|
|
|
R: FromLuaMulti<'lua>,
|
|
|
|
{
|
2017-05-24 23:13:58 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1)?;
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-24 23:13:58 -04:00
|
|
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
|
|
|
|
2017-06-17 22:40:09 -04:00
|
|
|
let status = ffi::lua_status(thread_state);
|
2017-06-17 23:50:40 -04:00
|
|
|
if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 {
|
|
|
|
return Err(LuaErrorKind::CoroutineInactive.into());
|
|
|
|
}
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
|
|
|
check_stack(thread_state, nargs)?;
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(thread_state, arg);
|
2017-06-17 23:50:40 -04:00
|
|
|
}
|
2017-06-17 22:40:09 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
handle_error(
|
|
|
|
lua.state,
|
|
|
|
resume_with_traceback(thread_state, lua.state, nargs),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let nresults = ffi::lua_gettop(thread_state);
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(lua.pop_value(thread_state));
|
2017-05-24 23:13:58 -04:00
|
|
|
}
|
2017-06-17 23:50:40 -04:00
|
|
|
R::from_lua_multi(results, lua)
|
2017-05-24 23:13:58 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the status of the thread.
|
2017-05-24 23:13:58 -04:00
|
|
|
pub fn status(&self) -> LuaResult<LuaThreadStatus> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1)?;
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-24 23:13:58 -04:00
|
|
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
|
|
|
|
let status = ffi::lua_status(thread_state);
|
|
|
|
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
|
|
|
|
Ok(LuaThreadStatus::Error)
|
|
|
|
} else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 {
|
|
|
|
Ok(LuaThreadStatus::Active)
|
|
|
|
} else {
|
|
|
|
Ok(LuaThreadStatus::Dead)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Kinds of metamethods that can be overridden.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
|
|
pub enum LuaMetaMethod {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `+` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Add,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `-` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Sub,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `*` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Mul,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `/` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Div,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `%` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Mod,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `^` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Pow,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The unary minus (`-`) operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Unm,
|
2017-06-18 00:28:46 -04:00
|
|
|
/// The floor division (//) operator.
|
|
|
|
IDiv,
|
|
|
|
/// The bitwise AND (&) operator.
|
|
|
|
BAnd,
|
|
|
|
/// The bitwise OR (|) operator.
|
|
|
|
BOr,
|
|
|
|
/// The bitwise XOR (binary ~) operator.
|
|
|
|
BXor,
|
|
|
|
/// The bitwise NOT (unary ~) operator.
|
|
|
|
BNot,
|
|
|
|
/// The bitwise left shift (<<) operator.
|
|
|
|
Shl,
|
|
|
|
/// The bitwise right shift (>>) operator.
|
|
|
|
Shr,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The string concatenation operator `..`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Concat,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The length operator `#`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Len,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `==` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Eq,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `<` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Lt,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `<=` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Le,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Index access `obj[key]`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Index,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Index write access `obj[key] = value`.
|
2017-05-21 19:50:59 -04:00
|
|
|
NewIndex,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The call "operator" `obj(arg1, args2, ...)`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Call,
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Stores methods of a userdata object.
|
|
|
|
///
|
|
|
|
/// Methods added will be added to the `__index` table on the metatable for the
|
|
|
|
/// userdata, so they can be called as `userdata:method(args)` as expected. If
|
|
|
|
/// there are any regular methods, and an `Index` metamethod is given, it will
|
2017-06-11 01:33:08 -04:00
|
|
|
/// be called as a *fallback* if the index doesn't match an existing regular
|
|
|
|
/// method.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub struct LuaUserDataMethods<T> {
|
|
|
|
methods: HashMap<String, LuaCallback>,
|
|
|
|
meta_methods: HashMap<LuaMetaMethod, LuaCallback>,
|
|
|
|
_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: LuaUserDataType> LuaUserDataMethods<T> {
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a regular method as a function which accepts a &T as the first
|
|
|
|
/// parameter.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_method<M>(&mut self, name: &str, method: M)
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
2017-06-15 10:26:39 -04:00
|
|
|
self.methods.insert(
|
|
|
|
name.to_owned(),
|
|
|
|
Self::box_method(method),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a regular method as a function which accepts a &mut T as the first
|
|
|
|
/// parameter.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_method_mut<M>(&mut self, name: &str, method: M)
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
2017-06-15 10:26:39 -04:00
|
|
|
self.methods.insert(
|
|
|
|
name.to_owned(),
|
|
|
|
Self::box_method_mut(method),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a regular method as a function which accepts generic arguments, the
|
|
|
|
/// first argument will always be a LuaUserData of type T.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_function<F>(&mut self, name: &str, function: F)
|
|
|
|
where F: 'static + for<'a, 'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
self.methods.insert(name.to_owned(), Box::new(function));
|
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a metamethod as a function which accepts a &T as the first
|
|
|
|
/// parameter. This can cause an error with certain binary metamethods that
|
|
|
|
/// can trigger if ony the right side has a metatable.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_method<M>(&mut self, meta: LuaMetaMethod, method: M)
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Self::box_method(method));
|
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a metamethod as a function which accepts a &mut T as the first
|
|
|
|
/// parameter. This can cause an error with certain binary metamethods that
|
|
|
|
/// can trigger if ony the right side has a metatable.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_method_mut<M>(&mut self, meta: LuaMetaMethod, method: M)
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Self::box_method_mut(method));
|
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
/// Add a metamethod as a function which accepts generic arguments.
|
|
|
|
/// Metamethods in Lua 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.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_function<F>(&mut self, meta: LuaMetaMethod, function: F)
|
|
|
|
where F: 'static + for<'a, 'lua> FnMut(&'lua Lua, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Box::new(function));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn box_method<M>(mut method: M) -> LuaCallback
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
2017-06-15 10:26:39 -04:00
|
|
|
let userdata = LuaUserData::from_lua(front, lua)?;
|
|
|
|
let userdata = userdata.borrow::<T>()?;
|
|
|
|
method(lua, &userdata, args)
|
|
|
|
} else {
|
|
|
|
Err("No userdata supplied as first argument to method".into())
|
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn box_method_mut<M>(mut method: M) -> LuaCallback
|
|
|
|
where M: 'static + for<'a, 'lua> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
2017-06-15 10:26:39 -04:00
|
|
|
let userdata = LuaUserData::from_lua(front, lua)?;
|
|
|
|
let mut userdata = userdata.borrow_mut::<T>()?;
|
|
|
|
method(lua, &mut userdata, args)
|
|
|
|
} else {
|
|
|
|
Err("No userdata supplied as first argument to method".into())
|
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for custom userdata types.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait LuaUserDataType: 'static + Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Adds custom methods and operators specific to this userdata.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn add_methods(_methods: &mut LuaUserDataMethods<Self>) {}
|
|
|
|
}
|
|
|
|
|
2017-06-11 01:33:08 -04:00
|
|
|
/// Handle to an internal instance of custom userdata. All userdata in this API
|
2017-06-17 21:23:17 -04:00
|
|
|
/// is based around `RefCell`, to best match the mutable semantics of the Lua
|
2017-06-11 01:33:08 -04:00
|
|
|
/// language.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaUserData<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaUserData<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Checks whether `T` is the type of this userdata.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn is<T: LuaUserDataType>(&self) -> bool {
|
|
|
|
self.inspect(|_: &RefCell<T>| Ok(())).is_ok()
|
|
|
|
}
|
|
|
|
|
2017-05-21 22:32:16 -04:00
|
|
|
/// Borrow this userdata out of the internal RefCell that is held in lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn borrow<T: LuaUserDataType>(&self) -> LuaResult<Ref<T>> {
|
|
|
|
self.inspect(|cell| Ok(cell.try_borrow()?))
|
|
|
|
}
|
|
|
|
|
2017-05-21 22:32:16 -04:00
|
|
|
/// Borrow mutably this userdata out of the internal RefCell that is held in lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn borrow_mut<T: LuaUserDataType>(&self) -> LuaResult<RefMut<T>> {
|
|
|
|
self.inspect(|cell| Ok(cell.try_borrow_mut()?))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inspect<'a, T, R, F>(&'a self, func: F) -> LuaResult<R>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: LuaUserDataType,
|
|
|
|
F: FnOnce(&'a RefCell<T>) -> LuaResult<R>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
stack_guard(lua.state, 0, move || {
|
|
|
|
check_stack(lua.state, 3)?;
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
let userdata = ffi::lua_touserdata(lua.state, -1);
|
|
|
|
if userdata.is_null() {
|
|
|
|
return Err("value not userdata".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
|
|
|
return Err("value has no metatable".into());
|
|
|
|
}
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_rawgeti(
|
|
|
|
lua.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
|
|
|
lua.userdata_metatable::<T>()? as ffi::lua_Integer,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
|
|
|
return Err("wrong metatable type for lua userdata".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = func(&*(userdata as *const RefCell<T>));
|
|
|
|
|
|
|
|
ffi::lua_pop(lua.state, 3);
|
|
|
|
res
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Top level Lua struct which holds the Lua state itself.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub struct Lua {
|
|
|
|
state: *mut ffi::lua_State,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: *mut ffi::lua_State,
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Lua {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
if !self.ephemeral {
|
2017-06-05 05:03:18 -04:00
|
|
|
ffi::lua_close(self.state);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lua {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a new Lua state.
|
|
|
|
///
|
|
|
|
/// Also loads the standard library.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn new() -> Lua {
|
|
|
|
unsafe {
|
|
|
|
let state = ffi::luaL_newstate();
|
|
|
|
ffi::luaL_openlibs(state);
|
|
|
|
|
|
|
|
stack_guard(state, 0, || {
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
state,
|
|
|
|
&LUA_USERDATA_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
|
|
|
|
|
|
|
let registered_userdata = ffi::lua_newuserdata(
|
|
|
|
state,
|
|
|
|
mem::size_of::<RefCell<HashMap<TypeId, c_int>>>(),
|
|
|
|
) as *mut RefCell<HashMap<TypeId, c_int>>;
|
2017-05-21 19:50:59 -04:00
|
|
|
ptr::write(registered_userdata, RefCell::new(HashMap::new()));
|
|
|
|
|
|
|
|
ffi::lua_newtable(state);
|
|
|
|
|
|
|
|
push_string(state, "__gc");
|
|
|
|
ffi::lua_pushcfunction(state, destructor::<RefCell<HashMap<TypeId, c_int>>>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_setmetatable(state, -2);
|
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
2017-05-21 19:50:59 -04:00
|
|
|
Ok(())
|
2017-06-11 01:12:25 -04:00
|
|
|
}).unwrap();
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
stack_guard(state, 0, || {
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
state,
|
|
|
|
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_newtable(state);
|
|
|
|
|
|
|
|
push_string(state, "__gc");
|
|
|
|
ffi::lua_pushcfunction(state, destructor::<LuaCallback>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(state, "__metatable");
|
|
|
|
ffi::lua_pushboolean(state, 0);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
2017-05-21 19:50:59 -04:00
|
|
|
Ok(())
|
2017-06-11 01:12:25 -04:00
|
|
|
}).unwrap();
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
stack_guard(state, 0, || {
|
|
|
|
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
|
|
|
|
|
|
|
push_string(state, "pcall");
|
|
|
|
ffi::lua_pushcfunction(state, safe_pcall);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(state, "xpcall");
|
|
|
|
ffi::lua_pushcfunction(state, safe_xpcall);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
Ok(())
|
2017-06-11 01:12:25 -04:00
|
|
|
}).unwrap();
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
Lua {
|
|
|
|
state,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: state,
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Execute a chunk of Lua code.
|
|
|
|
///
|
|
|
|
/// The source can be named by setting the `name` parameter. This is generally recommended as it
|
|
|
|
/// results in better error traces.
|
|
|
|
///
|
|
|
|
/// Returns the values returned by the chunk.
|
2017-06-18 08:31:38 -04:00
|
|
|
pub fn exec<'lua, R: FromLuaMulti<'lua>>(
|
2017-06-15 10:26:39 -04:00
|
|
|
&'lua self,
|
|
|
|
source: &str,
|
|
|
|
name: Option<&str>,
|
|
|
|
) -> LuaResult<R> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
2017-06-11 01:12:25 -04:00
|
|
|
let stack_start = ffi::lua_gettop(self.state);
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
self.state,
|
|
|
|
if let Some(name) = name {
|
|
|
|
let name = CString::new(name.to_owned())?;
|
|
|
|
ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
|
|
|
name.as_ptr(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
|
|
|
ptr::null(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
check_stack(self.state, 2)?;
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
self.state,
|
|
|
|
pcall_with_traceback(self.state, 0, ffi::LUA_MULTRET),
|
|
|
|
)?;
|
2017-06-11 01:12:25 -04:00
|
|
|
|
|
|
|
let nresults = ffi::lua_gettop(self.state) - stack_start;
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(self.pop_value(self.state));
|
2017-06-11 01:12:25 -04:00
|
|
|
}
|
|
|
|
R::from_lua_multi(results, self)
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Evaluate the given expression or chunk inside this Lua state.
|
|
|
|
///
|
|
|
|
/// If `source` is an expression, returns the value it evaluates to. Otherwise, returns the
|
|
|
|
/// values returned by the chunk (if any).
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn eval<'lua, R: FromLuaMulti<'lua>>(&'lua self, source: &str) -> LuaResult<R> {
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
let stack_start = ffi::lua_gettop(self.state);
|
2017-06-11 01:33:08 -04:00
|
|
|
// First, try interpreting the lua as an expression by adding
|
|
|
|
// "return", then as a statement. This is the same thing the
|
|
|
|
// actual lua repl does.
|
2017-05-21 19:50:59 -04:00
|
|
|
let return_source = "return ".to_owned() + source;
|
2017-06-15 10:26:39 -04:00
|
|
|
let mut res = ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
return_source.as_ptr() as *const c_char,
|
|
|
|
return_source.len(),
|
|
|
|
ptr::null(),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
if res == ffi::LUA_ERRSYNTAX {
|
|
|
|
ffi::lua_pop(self.state, 1);
|
2017-06-15 10:26:39 -04:00
|
|
|
res = ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
|
|
|
ptr::null(),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
handle_error(self.state, res)?;
|
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
check_stack(self.state, 2)?;
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
self.state,
|
|
|
|
pcall_with_traceback(self.state, 0, ffi::LUA_MULTRET),
|
|
|
|
)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let nresults = ffi::lua_gettop(self.state) - stack_start;
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(self.pop_value(self.state));
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
R::from_lua_multi(results, self)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Pass a `&str` slice to Lua, creating and returning a interned Lua string.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn create_string(&self, s: &str) -> LuaResult<LuaString> {
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 1)?;
|
|
|
|
ffi::lua_pushlstring(self.state, s.as_ptr() as *const c_char, s.len());
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaString(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates and returns a new table.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub fn create_table(&self) -> LuaResult<LuaTable> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 1)?;
|
|
|
|
ffi::lua_newtable(self.state);
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaTable(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table and fills it with values from an iterator.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> LuaResult<LuaTable>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
K: ToLua<'lua>,
|
|
|
|
V: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = (K, V)>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-05 01:46:45 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 3)?;
|
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
2017-06-15 16:27:39 -04:00
|
|
|
for (k, v) in cont {
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, k.to_lua(self)?);
|
|
|
|
self.push_value(self.state, v.to_lua(self)?);
|
2017-06-05 01:46:45 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
|
|
|
}
|
|
|
|
Ok(LuaTable(self.pop_ref(self.state)))
|
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table from an iterator of values, using `1..` as the keys.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> LuaResult<LuaTable>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = T>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-20 19:04:25 -04:00
|
|
|
self.create_table_from(cont.into_iter().enumerate().map(|(k, v)| (k + 1, v)))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn create_function<F>(&self, func: F) -> LuaResult<LuaFunction>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
F: 'static + for<'a> FnMut(&'a Lua, LuaMultiValue<'a>) -> LuaResult<LuaMultiValue<'a>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
self.create_callback_function(Box::new(func))
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Lua function into a new thread (or coroutine).
|
|
|
|
///
|
|
|
|
/// Equivalent to `coroutine.create`.
|
2017-05-24 23:13:58 -04:00
|
|
|
pub fn create_thread<'lua>(&'lua self, func: LuaFunction<'lua>) -> LuaResult<LuaThread<'lua>> {
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
|
|
|
check_stack(self.state, 1)?;
|
|
|
|
|
|
|
|
let thread_state = ffi::lua_newthread(self.state);
|
2017-05-25 00:43:35 -04:00
|
|
|
self.push_ref(thread_state, &func.0);
|
|
|
|
|
|
|
|
Ok(LuaThread(self.pop_ref(self.state)))
|
2017-05-24 23:13:58 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Create a Lua userdata object from a custom userdata type.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn create_userdata<T>(&self, data: T) -> LuaResult<LuaUserData>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: LuaUserDataType,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
|
|
|
check_stack(self.state, 2)?;
|
|
|
|
|
|
|
|
let data = RefCell::new(data);
|
2017-06-15 10:26:39 -04:00
|
|
|
let data_userdata =
|
|
|
|
ffi::lua_newuserdata(self.state, mem::size_of::<RefCell<T>>()) as
|
|
|
|
*mut RefCell<T>;
|
2017-05-21 19:50:59 -04:00
|
|
|
ptr::write(data_userdata, data);
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_rawgeti(
|
|
|
|
self.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
|
|
|
self.userdata_metatable::<T>()? as ffi::lua_Integer,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_setmetatable(self.state, -2);
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaUserData(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns a handle to the global environment.
|
2017-06-15 16:27:39 -04:00
|
|
|
pub fn globals(&self) -> LuaResult<LuaTable> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2017-06-11 01:12:25 -04:00
|
|
|
check_stack(self.state, 1)?;
|
|
|
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
|
|
|
Ok(LuaTable(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerces a Lua value to a string.
|
|
|
|
///
|
|
|
|
/// The value must be a string (in which case this is a no-op) or a number.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_string<'lua>(&'lua self, v: LuaValue<'lua>) -> LuaResult<LuaString<'lua>> {
|
|
|
|
match v {
|
|
|
|
LuaValue::String(s) => Ok(s),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 1)?;
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
if ffi::lua_tostring(self.state, -1).is_null() {
|
|
|
|
Err("cannot convert lua value to string".into())
|
|
|
|
} else {
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaString(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerces a Lua value to an integer.
|
|
|
|
///
|
|
|
|
/// The value must be an integer, or a floating point number or a string that can be converted
|
|
|
|
/// to an integer. Refer to the Lua manual for details.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_integer(&self, v: LuaValue) -> LuaResult<LuaInteger> {
|
|
|
|
match v {
|
|
|
|
LuaValue::Integer(i) => Ok(i),
|
|
|
|
LuaValue::Number(n) => Ok(n as LuaInteger),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 1)?;
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut isint = 0;
|
|
|
|
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
|
|
|
|
if isint == 0 {
|
|
|
|
Err("cannot convert lua value to integer".into())
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(self.state, 1);
|
|
|
|
Ok(i)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerce a Lua value to a number.
|
|
|
|
///
|
|
|
|
/// The value must be a number or a string that can be converted to a number. Refer to the Lua
|
|
|
|
/// manual for details.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_number(&self, v: LuaValue) -> LuaResult<LuaNumber> {
|
|
|
|
match v {
|
|
|
|
LuaValue::Integer(i) => Ok(i as LuaNumber),
|
|
|
|
LuaValue::Number(n) => Ok(n),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 1)?;
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut isnum = 0;
|
|
|
|
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
|
|
|
|
if isnum == 0 {
|
|
|
|
Err("cannot convert lua value to number".into())
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(self.state, 1);
|
|
|
|
Ok(n)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 00:47:48 -04:00
|
|
|
pub fn from<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> LuaResult<LuaValue<'lua>> {
|
2017-05-21 19:50:59 -04:00
|
|
|
t.to_lua(self)
|
|
|
|
}
|
|
|
|
|
2017-05-25 00:47:48 -04:00
|
|
|
pub fn to<'lua, T: FromLua<'lua>>(&'lua self, value: LuaValue<'lua>) -> LuaResult<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua(value, self)
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Packs up a value that implements `ToLuaMulti` into a `LuaMultiValue` instance.
|
|
|
|
///
|
|
|
|
/// This can be used to return arbitrary Lua values from a Rust function back to Lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn pack<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> LuaResult<LuaMultiValue<'lua>> {
|
|
|
|
t.to_lua_multi(self)
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Unpacks a `LuaMultiValue` instance into a value that implements `FromLuaMulti`.
|
|
|
|
///
|
|
|
|
/// This can be used to convert the arguments of a Rust function called by Lua.
|
2017-06-15 10:26:39 -04:00
|
|
|
pub fn unpack<'lua, T: FromLuaMulti<'lua>>(
|
|
|
|
&'lua self,
|
|
|
|
value: LuaMultiValue<'lua>,
|
|
|
|
) -> LuaResult<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua_multi(value, self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_callback_function(&self, func: LuaCallback) -> LuaResult<LuaFunction> {
|
|
|
|
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
callback_error(state, || {
|
|
|
|
let lua = Lua {
|
|
|
|
state: state,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: main_state(state),
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
let func = &mut *(ffi::lua_touserdata(state, ffi::lua_upvalueindex(1)) as
|
2017-06-15 10:26:39 -04:00
|
|
|
*mut LuaCallback);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let nargs = ffi::lua_gettop(state);
|
|
|
|
let mut args = LuaMultiValue::new();
|
|
|
|
for _ in 0..nargs {
|
2017-06-19 02:57:03 -04:00
|
|
|
args.push_front(lua.pop_value(state));
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let results = func(&lua, args)?;
|
|
|
|
let nresults = results.len() as c_int;
|
|
|
|
|
|
|
|
for r in results {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(state, r);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(nresults)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
|
|
|
check_stack(self.state, 2)?;
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
let func_userdata =
|
|
|
|
ffi::lua_newuserdata(self.state, mem::size_of::<LuaCallback>()) as
|
|
|
|
*mut LuaCallback;
|
2017-05-21 19:50:59 -04:00
|
|
|
ptr::write(func_userdata, func);
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
self.state,
|
|
|
|
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_gettable(self.state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
ffi::lua_setmetatable(self.state, -2);
|
|
|
|
|
|
|
|
ffi::lua_pushcclosure(self.state, callback_call_impl, 1);
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaFunction(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe fn push_value(&self, state: *mut ffi::lua_State, value: LuaValue) {
|
|
|
|
match value {
|
|
|
|
LuaValue::Nil => {
|
|
|
|
ffi::lua_pushnil(state);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Boolean(b) => {
|
|
|
|
ffi::lua_pushboolean(state, if b { 1 } else { 0 });
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::LightUserData(ud) => {
|
|
|
|
ffi::lua_pushlightuserdata(state, ud.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Integer(i) => {
|
|
|
|
ffi::lua_pushinteger(state, i);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Number(n) => {
|
|
|
|
ffi::lua_pushnumber(state, n);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::String(s) => {
|
|
|
|
self.push_ref(state, &s.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Table(t) => {
|
|
|
|
self.push_ref(state, &t.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Function(f) => {
|
|
|
|
self.push_ref(state, &f.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::UserData(ud) => {
|
|
|
|
self.push_ref(state, &ud.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Thread(t) => {
|
|
|
|
self.push_ref(state, &t.0);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe fn pop_value(&self, state: *mut ffi::lua_State) -> LuaValue {
|
|
|
|
match ffi::lua_type(state, -1) {
|
2017-05-25 00:43:35 -04:00
|
|
|
ffi::LUA_TNIL => {
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaNil
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TBOOLEAN => {
|
|
|
|
let b = LuaValue::Boolean(ffi::lua_toboolean(state, -1) != 0);
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
b
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TLIGHTUSERDATA => {
|
|
|
|
let ud = LuaValue::LightUserData(LightUserData(ffi::lua_touserdata(state, -1)));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
ud
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TNUMBER => {
|
|
|
|
if ffi::lua_isinteger(state, -1) != 0 {
|
|
|
|
let i = LuaValue::Integer(ffi::lua_tointeger(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
i
|
2017-05-25 00:43:35 -04:00
|
|
|
} else {
|
|
|
|
let n = LuaValue::Number(ffi::lua_tonumber(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
n
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TSTRING => LuaValue::String(LuaString(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TTABLE => LuaValue::Table(LuaTable(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TFUNCTION => LuaValue::Function(LuaFunction(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TUSERDATA => LuaValue::UserData(LuaUserData(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TTHREAD => LuaValue::Thread(LuaThread(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
_ => unreachable!("LUA_TNONE in pop_value"),
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn push_ref(&self, state: *mut ffi::lua_State, lref: &LuaRef) {
|
2017-06-15 10:26:39 -04:00
|
|
|
assert_eq!(
|
|
|
|
lref.lua.main_state,
|
|
|
|
self.main_state,
|
|
|
|
"Lua instance passed LuaValue created from a different Lua"
|
|
|
|
);
|
|
|
|
|
|
|
|
ffi::lua_rawgeti(
|
|
|
|
state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
|
|
|
lref.registry_id as ffi::lua_Integer,
|
|
|
|
);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
// Pops the topmost element of the stack and stores a reference to it in the
|
|
|
|
// registry.
|
|
|
|
//
|
|
|
|
// This pins the object, preventing garbage collection until the returned
|
|
|
|
// `LuaRef` is dropped.
|
2017-05-25 00:43:35 -04:00
|
|
|
unsafe fn pop_ref(&self, state: *mut ffi::lua_State) -> LuaRef {
|
|
|
|
let registry_id = ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
LuaRef {
|
|
|
|
lua: self,
|
|
|
|
registry_id: registry_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe fn userdata_metatable<T: LuaUserDataType>(&self) -> LuaResult<c_int> {
|
|
|
|
// Used if both an __index metamethod is set and regular methods, checks methods table
|
|
|
|
// first, then __index metamethod.
|
|
|
|
unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
ffi::lua_pushvalue(state, -1);
|
|
|
|
ffi::lua_gettable(state, ffi::lua_upvalueindex(1));
|
|
|
|
if ffi::lua_isnil(state, -1) == 0 {
|
|
|
|
ffi::lua_insert(state, -3);
|
|
|
|
ffi::lua_pop(state, 2);
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(2));
|
|
|
|
ffi::lua_insert(state, -3);
|
|
|
|
ffi::lua_call(state, 2, 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_guard(self.state, 0, move || {
|
|
|
|
check_stack(self.state, 3)?;
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
self.state,
|
|
|
|
&LUA_USERDATA_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_gettable(self.state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
let registered_userdata = ffi::lua_touserdata(self.state, -1) as
|
2017-06-15 10:26:39 -04:00
|
|
|
*mut RefCell<HashMap<TypeId, c_int>>;
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut map = (*registered_userdata).borrow_mut();
|
|
|
|
ffi::lua_pop(self.state, 1);
|
|
|
|
|
|
|
|
match map.entry(TypeId::of::<T>()) {
|
|
|
|
HashMapEntry::Occupied(entry) => Ok(*entry.get()),
|
|
|
|
HashMapEntry::Vacant(entry) => {
|
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
|
|
|
let mut methods = LuaUserDataMethods {
|
|
|
|
methods: HashMap::new(),
|
|
|
|
meta_methods: HashMap::new(),
|
|
|
|
_type: PhantomData,
|
|
|
|
};
|
|
|
|
T::add_methods(&mut methods);
|
|
|
|
|
|
|
|
let has_methods = !methods.methods.is_empty();
|
|
|
|
|
|
|
|
if has_methods {
|
|
|
|
push_string(self.state, "__index");
|
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
|
|
|
check_stack(self.state, methods.methods.len() as c_int * 2)?;
|
|
|
|
for (k, m) in methods.methods {
|
|
|
|
push_string(self.state, &k);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
|
|
|
LuaValue::Function(self.create_callback_function(m)?),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
check_stack(self.state, methods.meta_methods.len() as c_int * 2)?;
|
|
|
|
for (k, m) in methods.meta_methods {
|
|
|
|
if k == LuaMetaMethod::Index && has_methods {
|
|
|
|
push_string(self.state, "__index");
|
|
|
|
ffi::lua_pushvalue(self.state, -1);
|
|
|
|
ffi::lua_gettable(self.state, -3);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
|
|
|
LuaValue::Function(self.create_callback_function(m)?),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pushcclosure(self.state, meta_index_impl, 2);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
} else {
|
|
|
|
let name = match k {
|
|
|
|
LuaMetaMethod::Add => "__add",
|
|
|
|
LuaMetaMethod::Sub => "__sub",
|
|
|
|
LuaMetaMethod::Mul => "__mul",
|
|
|
|
LuaMetaMethod::Div => "__div",
|
|
|
|
LuaMetaMethod::Mod => "__mod",
|
|
|
|
LuaMetaMethod::Pow => "__pow",
|
|
|
|
LuaMetaMethod::Unm => "__unm",
|
2017-06-18 00:28:46 -04:00
|
|
|
LuaMetaMethod::IDiv => "__idiv",
|
|
|
|
LuaMetaMethod::BAnd => "__band",
|
|
|
|
LuaMetaMethod::BOr => "__bor",
|
|
|
|
LuaMetaMethod::BXor => "__bxor",
|
|
|
|
LuaMetaMethod::BNot => "__bnot",
|
|
|
|
LuaMetaMethod::Shl => "__shl",
|
|
|
|
LuaMetaMethod::Shr => "__shr",
|
2017-05-21 19:50:59 -04:00
|
|
|
LuaMetaMethod::Concat => "__concat",
|
|
|
|
LuaMetaMethod::Len => "__len",
|
|
|
|
LuaMetaMethod::Eq => "__eq",
|
|
|
|
LuaMetaMethod::Lt => "__lt",
|
|
|
|
LuaMetaMethod::Le => "__le",
|
|
|
|
LuaMetaMethod::Index => "__index",
|
|
|
|
LuaMetaMethod::NewIndex => "__newIndex",
|
|
|
|
LuaMetaMethod::Call => "__call",
|
|
|
|
};
|
|
|
|
push_string(self.state, name);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
|
|
|
LuaValue::Function(self.create_callback_function(m)?),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push_string(self.state, "__gc");
|
|
|
|
ffi::lua_pushcfunction(self.state, destructor::<RefCell<T>>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(self.state, "__metatable");
|
|
|
|
ffi::lua_pushboolean(self.state, 0);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let id = ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
entry.insert(id);
|
|
|
|
Ok(id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static LUA_USERDATA_REGISTRY_KEY: u8 = 0;
|
|
|
|
static FUNCTION_METATABLE_REGISTRY_KEY: u8 = 0;
|