I believe this is all the external API changes necessary for 'm' safety

This commit is contained in:
kyren 2017-12-03 23:45:00 -05:00
parent e80e7d4540
commit d0ff10b528
8 changed files with 73 additions and 66 deletions

View File

@ -41,13 +41,13 @@ fn examples() -> Result<()> {
// You can create and manage lua tables
let array_table = lua.create_table();
let array_table = lua.create_table()?;
array_table.set(1, "one")?;
array_table.set(2, "two")?;
array_table.set(3, "three")?;
assert_eq!(array_table.len()?, 3);
let map_table = lua.create_table();
let map_table = lua.create_table()?;
map_table.set("one", 1)?;
map_table.set("two", 2)?;
map_table.set("three", 3)?;
@ -91,7 +91,7 @@ fn examples() -> Result<()> {
// Lua callbacks return rlua::Result, an Ok value is a normal return, and an Err return
// turns into a Lua 'error'. Again, any type that is convertible to lua may be returned.
Ok(list1 == list2)
});
})?;
globals.set("check_equal", check_equal)?;
// You can also accept runtime variadic arguments to rust callbacks.
@ -99,7 +99,7 @@ fn examples() -> Result<()> {
let join = lua.create_function(|_, strings: Variadic<String>| {
// (This is quadratic!, it's just an example!)
Ok(strings.iter().fold("".to_owned(), |a, b| a + b))
});
})?;
globals.set("join", join)?;
assert_eq!(
@ -132,7 +132,7 @@ fn examples() -> Result<()> {
}
}
let vec2_constructor = lua.create_function(|_, (x, y): (f32, f32)| Ok(Vec2(x, y)));
let vec2_constructor = lua.create_function(|_, (x, y): (f32, f32)| Ok(Vec2(x, y)))?;
globals.set("vec2", vec2_constructor)?;
assert!(lua.eval::<f32>("(vec2(1, 2) + vec2(2, 2)):magnitude()", None)? - 5.0 < f32::EPSILON);

View File

@ -111,7 +111,7 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
impl<'lua, T: UserData> ToLua<'lua> for T {
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::UserData(lua.create_userdata(self)))
Ok(Value::UserData(lua.create_userdata(self)?))
}
}
@ -184,7 +184,7 @@ impl<'lua> FromLua<'lua> for LightUserData {
impl<'lua> ToLua<'lua> for StdString {
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::String(lua.create_string(&self)))
Ok(Value::String(lua.create_string(&self)?))
}
}
@ -196,7 +196,7 @@ impl<'lua> FromLua<'lua> for StdString {
impl<'lua, 'a> ToLua<'lua> for &'a str {
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
Ok(Value::String(lua.create_string(self)))
Ok(Value::String(lua.create_string(self)?))
}
}

View File

@ -545,23 +545,25 @@ impl Lua {
}
/// Pass a `&str` slice to Lua, creating and returning an interned Lua string.
pub fn create_string(&self, s: &str) -> String {
pub fn create_string(&self, s: &str) -> Result<String> {
unsafe {
stack_guard(self.state, 0, || {
check_stack(self.state, 2);
ffi::lua_pushlstring(self.state, s.as_ptr() as *const c_char, s.len());
String(self.pop_ref(self.state))
Ok(String(self.pop_ref(self.state)))
})
}
}
/// Creates and returns a new table.
pub fn create_table(&self) -> Table {
pub fn create_table(&self) -> Result<Table> {
unsafe {
stack_guard(self.state, 0, || {
check_stack(self.state, 2);
ffi::lua_newtable(self.state);
Table(self.pop_ref(self.state))
check_stack(self.state, 4);
protect_lua_call(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
Ok(Table(self.pop_ref(self.state)))
})
}
}
@ -575,8 +577,10 @@ impl Lua {
{
unsafe {
stack_err_guard(self.state, 0, || {
check_stack(self.state, 3);
ffi::lua_newtable(self.state);
check_stack(self.state, 6);
protect_lua_call(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
for (k, v) in cont {
self.push_value(self.state, k.to_lua(self)?);
@ -640,7 +644,7 @@ impl Lua {
/// # try_main().unwrap();
/// # }
/// ```
pub fn create_function<'lua, A, R, F>(&'lua self, mut func: F) -> Function<'lua>
pub fn create_function<'lua, A, R, F>(&'lua self, mut func: F) -> Result<Function<'lua>>
where
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
@ -654,7 +658,7 @@ impl Lua {
/// Wraps a Lua function into a new thread (or coroutine).
///
/// Equivalent to `coroutine.create`.
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Thread<'lua> {
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
unsafe {
stack_guard(self.state, 0, move || {
check_stack(self.state, 2);
@ -662,18 +666,18 @@ impl Lua {
let thread_state = ffi::lua_newthread(self.state);
self.push_ref(thread_state, &func.0);
Thread(self.pop_ref(self.state))
Ok(Thread(self.pop_ref(self.state)))
})
}
}
/// Create a Lua userdata object from a custom userdata type.
pub fn create_userdata<T>(&self, data: T) -> AnyUserData
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
where
T: UserData,
{
unsafe {
stack_guard(self.state, 0, move || {
stack_err_guard(self.state, 0, move || {
check_stack(self.state, 3);
push_userdata::<RefCell<T>>(self.state, RefCell::new(data));
@ -681,12 +685,12 @@ impl Lua {
ffi::lua_rawgeti(
self.state,
ffi::LUA_REGISTRYINDEX,
self.userdata_metatable::<T>() as ffi::lua_Integer,
self.userdata_metatable::<T>()? as ffi::lua_Integer,
);
ffi::lua_setmetatable(self.state, -2);
AnyUserData(self.pop_ref(self.state))
Ok(AnyUserData(self.pop_ref(self.state)))
})
}
}
@ -942,7 +946,7 @@ impl Lua {
}
}
pub(crate) unsafe fn userdata_metatable<T: UserData>(&self) -> c_int {
pub(crate) unsafe fn userdata_metatable<T: UserData>(&self) -> Result<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 {
@ -963,7 +967,7 @@ impl Lua {
}
}
stack_guard(self.state, 0, move || {
stack_err_guard(self.state, 0, move || {
check_stack(self.state, 5);
ffi::lua_pushlightuserdata(
@ -975,7 +979,7 @@ impl Lua {
ffi::lua_pop(self.state, 1);
if let Some(table_id) = (*registered_userdata).get(&TypeId::of::<T>()) {
return *table_id;
return Ok(*table_id);
}
let mut methods = UserDataMethods {
@ -997,7 +1001,7 @@ impl Lua {
push_string(self.state, &k);
self.push_value(
self.state,
Value::Function(self.create_callback_function(m)),
Value::Function(self.create_callback_function(m)?),
);
ffi::lua_rawset(self.state, -3);
}
@ -1012,7 +1016,7 @@ impl Lua {
ffi::lua_gettable(self.state, -3);
self.push_value(
self.state,
Value::Function(self.create_callback_function(m)),
Value::Function(self.create_callback_function(m)?),
);
ffi::lua_pushcclosure(self.state, meta_index_impl, 2);
ffi::lua_rawset(self.state, -3);
@ -1045,7 +1049,7 @@ impl Lua {
push_string(self.state, name);
self.push_value(
self.state,
Value::Function(self.create_callback_function(m)),
Value::Function(self.create_callback_function(m)?),
);
ffi::lua_rawset(self.state, -3);
}
@ -1061,7 +1065,7 @@ impl Lua {
let id = ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX);
(*registered_userdata).insert(TypeId::of::<T>(), id);
id
Ok(id)
})
}
@ -1173,7 +1177,7 @@ impl Lua {
}
}
fn create_callback_function<'lua>(&'lua self, func: Callback<'lua>) -> Function<'lua> {
fn create_callback_function<'lua>(&'lua self, func: Callback<'lua>) -> Result<Function<'lua>> {
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
callback_error(state, || {
let lua = Lua {
@ -1227,7 +1231,7 @@ impl Lua {
ffi::lua_pushcclosure(self.state, callback_call_impl, 1);
Function(self.pop_ref(self.state))
Ok(Function(self.pop_ref(self.state)))
})
}
}

View File

@ -68,7 +68,7 @@ impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
///
/// let add = lua.create_function(|_, vals: Variadic<f64>| -> Result<f64> {
/// Ok(vals.iter().sum())
/// });
/// }).unwrap();
/// lua.globals().set("add", add)?;
/// assert_eq!(lua.eval::<f64>("add(3, 2, 5)", None)?, 10.0);
/// # Ok(())

View File

@ -121,7 +121,7 @@ mod tests {
F: FnOnce(String),
{
let lua = Lua::new();
let string = lua.create_string(s);
let string = lua.create_string(s).unwrap();
f(string);
}

View File

@ -452,7 +452,7 @@ mod tests {
let lua = Lua::new();
let globals = lua.globals();
globals.set("table", lua.create_table()).unwrap();
globals.set("table", lua.create_table().unwrap()).unwrap();
let table1: Table = globals.get("table").unwrap();
let table2: Table = globals.get("table").unwrap();
@ -588,10 +588,10 @@ mod tests {
fn test_metatable() {
let lua = Lua::new();
let table = lua.create_table();
let metatable = lua.create_table();
let table = lua.create_table().unwrap();
let metatable = lua.create_table().unwrap();
metatable
.set("__index", lua.create_function(|_, ()| Ok("index_value")))
.set("__index", lua.create_function(|_, ()| Ok("index_value")).unwrap())
.unwrap();
table.set_metatable(Some(metatable));
assert_eq!(table.get::<_, String>("any_key").unwrap(), "index_value");

View File

@ -142,7 +142,7 @@ fn test_rust_function() {
).unwrap();
let lua_function = globals.get::<_, Function>("lua_function").unwrap();
let rust_function = lua.create_function(|_, ()| Ok("hello"));
let rust_function = lua.create_function(|_, ()| Ok("hello")).unwrap();
globals.set("rust_function", rust_function).unwrap();
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
@ -271,7 +271,7 @@ fn test_error() {
).unwrap();
let rust_error_function =
lua.create_function(|_, ()| -> Result<()> { Err(TestError.to_lua_err()) });
lua.create_function(|_, ()| -> Result<()> { Err(TestError.to_lua_err()) }).unwrap();
globals
.set("rust_error_function", rust_error_function)
.unwrap();
@ -338,7 +338,7 @@ fn test_error() {
)?;
let rust_panic_function = lua.create_function(|_, ()| -> Result<()> {
panic!("expected panic, this panic should be caught in rust")
});
}).unwrap();
globals.set("rust_panic_function", rust_panic_function)?;
let rust_panic = globals.get::<_, Function>("rust_panic")?;
@ -364,7 +364,7 @@ fn test_error() {
)?;
let rust_panic_function = lua.create_function(|_, ()| -> Result<()> {
panic!("expected panic, this panic should be caught in rust")
});
}).unwrap();
globals.set("rust_panic_function", rust_panic_function)?;
let rust_panic = globals.get::<_, Function>("rust_panic")?;
@ -393,7 +393,7 @@ fn test_thread() {
"#,
None,
).unwrap(),
);
).unwrap();
assert_eq!(thread.status(), ThreadStatus::Resumable);
assert_eq!(thread.resume::<_, i64>(0).unwrap(), 0);
@ -418,7 +418,7 @@ fn test_thread() {
"#,
None,
).unwrap(),
);
).unwrap();
for i in 0..4 {
accumulate.resume::<_, ()>(i).unwrap();
@ -472,8 +472,8 @@ fn test_result_conversions() {
Ok(Err::<String, _>(
"only through failure can we succeed".to_lua_err(),
))
});
let ok = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned())));
}).unwrap();
let ok = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned()))).unwrap();
globals.set("err", err).unwrap();
globals.set("ok", ok).unwrap();
@ -519,7 +519,7 @@ fn test_num_conversion() {
#[test]
fn coroutine_from_closure() {
let lua = Lua::new();
let thrd_main = lua.create_function(|_, ()| Ok(()));
let thrd_main = lua.create_function(|_, ()| Ok(())).unwrap();
lua.globals().set("main", thrd_main).unwrap();
let thrd: Thread = lua.eval("coroutine.create(main)", None).unwrap();
thrd.resume::<_, ()>(()).unwrap();
@ -533,9 +533,9 @@ fn coroutine_panic() {
// whoops, 'main' has a wrong type
let _coro: u32 = lua.globals().get("main").unwrap();
Ok(())
});
}).unwrap();
lua.globals().set("main", thrd_main.clone()).unwrap();
let thrd: Thread = lua.create_thread(thrd_main);
let thrd: Thread = lua.create_thread(thrd_main).unwrap();
thrd.resume::<_, ()>(()).unwrap();
}
@ -625,7 +625,7 @@ fn test_recursive_callback_panic() {
}
Ok(())
});
}).unwrap();
lua.globals().set("f", f).unwrap();
lua.globals()
.get::<_, Function>("f")

View File

@ -319,8 +319,12 @@ pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
impl<'lua> AnyUserData<'lua> {
/// Checks whether the type of this userdata is `T`.
pub fn is<T: UserData>(&self) -> bool {
self.inspect(|_: &RefCell<T>| ()).is_some()
pub fn is<T: UserData>(&self) -> Result<bool> {
match self.inspect(|_: &RefCell<T>| Ok(())) {
Ok(()) => Ok(true),
Err(Error::UserDataTypeMismatch) => Ok(false),
Err(err) => Err(err),
}
}
/// Borrow this userdata immutably if it is of type `T`.
@ -331,7 +335,6 @@ impl<'lua> AnyUserData<'lua> {
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
pub fn borrow<T: UserData>(&self) -> Result<Ref<T>> {
self.inspect(|cell| Ok(cell.try_borrow().map_err(|_| Error::UserDataBorrowError)?))
.ok_or(Error::UserDataTypeMismatch)?
}
/// Borrow this userdata mutably if it is of type `T`.
@ -344,13 +347,13 @@ impl<'lua> AnyUserData<'lua> {
self.inspect(|cell| {
Ok(cell.try_borrow_mut()
.map_err(|_| Error::UserDataBorrowMutError)?)
}).ok_or(Error::UserDataTypeMismatch)?
})
}
fn inspect<'a, T, R, F>(&'a self, func: F) -> Option<R>
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
where
T: UserData,
F: FnOnce(&'a RefCell<T>) -> R,
F: FnOnce(&'a RefCell<T>) -> Result<R>,
{
unsafe {
let lua = self.0.lua;
@ -368,16 +371,16 @@ impl<'lua> AnyUserData<'lua> {
ffi::lua_rawgeti(
lua.state,
ffi::LUA_REGISTRYINDEX,
lua.userdata_metatable::<T>() as ffi::lua_Integer,
lua.userdata_metatable::<T>()? as ffi::lua_Integer,
);
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
ffi::lua_pop(lua.state, 3);
None
Err(Error::UserDataTypeMismatch)
} else {
let res = func(&*get_userdata::<RefCell<T>>(lua.state, -3));
ffi::lua_pop(lua.state, 3);
Some(res)
res
}
})
}
@ -401,13 +404,13 @@ mod tests {
let lua = Lua::new();
let userdata1 = lua.create_userdata(UserData1(1));
let userdata2 = lua.create_userdata(UserData2(Box::new(2)));
let userdata1 = lua.create_userdata(UserData1(1)).unwrap();
let userdata2 = lua.create_userdata(UserData2(Box::new(2))).unwrap();
assert!(userdata1.is::<UserData1>());
assert!(!userdata1.is::<UserData2>());
assert!(userdata2.is::<UserData2>());
assert!(!userdata2.is::<UserData1>());
assert!(userdata1.is::<UserData1>().unwrap());
assert!(!userdata1.is::<UserData2>().unwrap());
assert!(userdata2.is::<UserData2>().unwrap());
assert!(!userdata2.is::<UserData1>().unwrap());
assert_eq!(userdata1.borrow::<UserData1>().unwrap().0, 1);
assert_eq!(*userdata2.borrow::<UserData2>().unwrap().0, 2);
@ -429,7 +432,7 @@ mod tests {
let lua = Lua::new();
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42));
let userdata = lua.create_userdata(MyUserData(42)).unwrap();
globals.set("userdata", userdata.clone()).unwrap();
lua.exec::<()>(
r#"