Allow non-utf8 Lua source in load / exec / eval

This commit is contained in:
kyren 2018-10-01 06:00:21 -04:00
parent 8538874dd3
commit 65d8ad2f86
14 changed files with 99 additions and 83 deletions

View file

@ -27,7 +27,7 @@ fn main() -> Result<()> {
// You can load and evaluate lua code. The second parameter here gives the chunk a better name
// when lua error messages are printed.
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
global = 'foo'..'bar'
"#,
@ -35,9 +35,9 @@ fn main() -> Result<()> {
)?;
assert_eq!(globals.get::<_, String>("global")?, "foobar");
assert_eq!(lua.eval::<i32>("1 + 1", None)?, 2);
assert_eq!(lua.eval::<bool>("false == false", None)?, true);
assert_eq!(lua.eval::<i32>("return 1 + 2", None)?, 3);
assert_eq!(lua.eval::<_, i32>("1 + 1", None)?, 2);
assert_eq!(lua.eval::<_, bool>("false == false", None)?, true);
assert_eq!(lua.eval::<_, i32>("return 1 + 2", None)?, 3);
// You can create and manage lua tables
@ -59,7 +59,7 @@ fn main() -> Result<()> {
globals.set("array_table", array_table)?;
globals.set("map_table", map_table)?;
lua.eval::<()>(
lua.eval::<_, ()>(
r#"
for k, v in pairs(array_table) do
print(k, v)
@ -110,14 +110,17 @@ fn main() -> Result<()> {
globals.set("join", join)?;
assert_eq!(
lua.eval::<bool>(r#"check_equal({"a", "b", "c"}, {"a", "b", "c"})"#, None)?,
lua.eval::<_, bool>(r#"check_equal({"a", "b", "c"}, {"a", "b", "c"})"#, None)?,
true
);
assert_eq!(
lua.eval::<bool>(r#"check_equal({"a", "b", "c"}, {"d", "e", "f"})"#, None)?,
lua.eval::<_, bool>(r#"check_equal({"a", "b", "c"}, {"d", "e", "f"})"#, None)?,
false
);
assert_eq!(lua.eval::<String>(r#"join("a", "b", "c")"#, None)?, "abc");
assert_eq!(
lua.eval::<_, String>(r#"join("a", "b", "c")"#, None)?,
"abc"
);
// You can create userdata with methods and metamethods defined on them.
// Here's a worked example that shows many of the features of this API
@ -143,7 +146,7 @@ fn main() -> Result<()> {
globals.set("vec2", vec2_constructor)?;
assert!(
(lua.eval::<f32>("(vec2(1, 2) + vec2(2, 2)):magnitude()", None)? - 5.0).abs()
(lua.eval::<_, f32>("(vec2(1, 2) + vec2(2, 2)):magnitude()", None)? - 5.0).abs()
< f32::EPSILON
);
@ -168,7 +171,7 @@ fn main() -> Result<()> {
})?,
)?;
lua.eval::<()>("sketchy()", None)
lua.eval::<_, ()>("sketchy()", None)
})?;
assert_eq!(rust_val, 42);
@ -178,7 +181,7 @@ fn main() -> Result<()> {
// run our 'sketchy' function outside of the scope, the function we created will have been
// invalidated and we will generate an error. If our function wasn't invalidated, we might be
// able to improperly access the destroyed `rust_val` which would be unsafe.
assert!(lua.eval::<()>("sketchy()", None).is_err());
assert!(lua.eval::<_, ()>("sketchy()", None).is_err());
Ok(())
}

View file

@ -20,7 +20,7 @@ fn main() {
Err(_) => return,
}
match lua.eval::<MultiValue>(&line, None) {
match lua.eval::<_, MultiValue>(&line, None) {
Ok(values) => {
editor.add_history_entry(line);
println!(

View file

@ -77,10 +77,14 @@ impl Lua {
/// results in better error traces.
///
/// Equivalent to Lua's `load` function.
pub fn load(&self, source: &str, name: Option<&str>) -> Result<Function> {
pub fn load<S>(&self, source: &S, name: Option<&str>) -> Result<Function>
where
S: ?Sized + AsRef<[u8]>,
{
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 1);
let source = source.as_ref();
match if let Some(name) = name {
let name =
@ -115,11 +119,15 @@ impl Lua {
/// function with no arguments.
///
/// Returns the values returned by the chunk.
pub fn exec<'lua, R: FromLuaMulti<'lua>>(
pub fn exec<'lua, S, R: FromLuaMulti<'lua>>(
&'lua self,
source: &str,
source: &S,
name: Option<&str>,
) -> Result<R> {
) -> Result<R>
where
S: ?Sized + AsRef<[u8]>,
R: FromLuaMulti<'lua>,
{
self.load(source, name)?.call(())
}
@ -127,15 +135,17 @@ impl Lua {
///
/// If `source` is an expression, returns the value it evaluates to. Otherwise, returns the
/// values returned by the chunk (if any).
pub fn eval<'lua, R: FromLuaMulti<'lua>>(
&'lua self,
source: &str,
name: Option<&str>,
) -> Result<R> {
pub fn eval<'lua, S, R>(&'lua self, source: &S, name: Option<&str>) -> Result<R>
where
S: ?Sized + AsRef<[u8]>,
R: FromLuaMulti<'lua>,
{
// 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.
self.load(&format!("return {}", source), name)
let mut return_source = "return ".as_bytes().to_vec();
return_source.extend(source.as_ref());
self.load(&return_source, name)
.or_else(|_| self.load(source, name))?
.call(())
}
@ -143,7 +153,10 @@ impl Lua {
/// Create and return an interned Lua string. Lua strings can be arbitrary [u8] data including
/// embedded nulls, so in addition to `&str` and `&String`, you can also pass plain `&[u8]`
/// here.
pub fn create_string<S: ?Sized + AsRef<[u8]>>(&self, s: &S) -> Result<String> {
pub fn create_string<S>(&self, s: &S) -> Result<String>
where
S: ?Sized + AsRef<[u8]>,
{
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 4);

View file

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

View file

@ -32,7 +32,7 @@ impl<'lua> Table<'lua> {
///
/// globals.set("assertions", cfg!(debug_assertions))?;
///
/// lua.exec::<()>(r#"
/// lua.exec::<_, ()>(r#"
/// if assertions == true then
/// -- ...
/// elseif assertions == false then

View file

@ -219,7 +219,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
/// // `MyUserData` now implements `ToLua`:
/// lua.globals().set("myobject", MyUserData(123))?;
///
/// lua.exec::<()>("assert(type(myobject) == 'userdata')", None)?;
/// lua.exec::<_, ()>("assert(type(myobject) == 'userdata')", None)?;
/// # Ok(())
/// # }
/// # fn main() {
@ -257,7 +257,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
///
/// lua.globals().set("myobject", MyUserData(123))?;
///
/// lua.exec::<()>(r#"
/// lua.exec::<_, ()>(r#"
/// assert(myobject:get() == 123)
/// myobject:add(7)
/// assert(myobject:get() == 130)

View file

@ -6,7 +6,7 @@ use rlua::{Function, Lua, String};
fn test_function() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function concat(arg1, arg2)
return arg1 .. arg2
@ -23,7 +23,7 @@ fn test_function() {
fn test_bind() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function concat(...)
local res = ""
@ -50,7 +50,7 @@ fn test_bind() {
fn test_rust_function() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function lua_function()
return rust_function()

View file

@ -60,7 +60,7 @@ fn scope_drop() {
});
assert_eq!(Rc::strong_count(&rc), 1);
match lua.exec::<()>("test:method()", None) {
match lua.exec::<_, ()>("test:method()", None) {
Err(Error::CallbackError { .. }) => {}
r => panic!("improper return for destructed userdata: {:?}", r),
};
@ -162,7 +162,7 @@ fn scope_userdata_functions() {
let lua = Lua::new();
let f = lua
.exec::<Function>(
.exec::<_, Function>(
r#"
i = 0
return function(u)
@ -197,7 +197,7 @@ fn scope_userdata_mismatch() {
}
let lua = Lua::new();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function okay(a, b)
a.inc(a)

View file

@ -30,7 +30,7 @@ fn compare() {
#[test]
fn string_views() {
let lua = Lua::new();
lua.eval::<()>(
lua.eval::<_, ()>(
r#"
ok = "null bytes are valid utf-8, wh\0 knew?"
err = "but \xff isn't :("

View file

@ -27,7 +27,7 @@ fn test_table() {
assert_eq!(table2.get::<_, String>("foo").unwrap(), "bar");
assert_eq!(table1.get::<_, String>("baz").unwrap(), "baf");
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
table1 = {1, 2, 3, 4, 5}
table2 = {}
@ -100,7 +100,7 @@ fn test_table() {
fn test_table_scope() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
touter = {
tin = {1, 2, 3}
@ -149,7 +149,7 @@ fn test_metatable() {
fn test_table_error() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
table = {}
setmetatable(table, {

View file

@ -28,7 +28,7 @@ fn test_debug() {
Value::Table(_) => {}
val => panic!("Expected table for debug library, got {:#?}", val),
}
let traceback_output = lua.eval::<String>("debug.traceback()", None).unwrap();
let traceback_output = lua.eval::<_, String>("debug.traceback()", None).unwrap();
assert_eq!(
traceback_output.to_str().unwrap().split("\n").next(),
"stack traceback:".into()
@ -39,7 +39,7 @@ fn test_debug() {
fn test_exec() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
res = 'foo'..'bar'
"#,
@ -74,10 +74,10 @@ fn test_exec() {
#[test]
fn test_eval() {
let lua = Lua::new();
assert_eq!(lua.eval::<i32>("1 + 1", None).unwrap(), 2);
assert_eq!(lua.eval::<bool>("false == false", None).unwrap(), true);
assert_eq!(lua.eval::<i32>("return 1 + 2", None).unwrap(), 3);
match lua.eval::<()>("if true then", None) {
assert_eq!(lua.eval::<_, i32>("1 + 1", None).unwrap(), 2);
assert_eq!(lua.eval::<_, bool>("false == false", None).unwrap(), true);
assert_eq!(lua.eval::<_, i32>("return 1 + 2", None).unwrap(), 3);
match lua.eval::<_, ()>("if true then", None) {
Err(Error::SyntaxError {
incomplete_input: true,
..
@ -93,7 +93,7 @@ fn test_eval() {
fn test_lua_multi() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function concat(arg1, arg2)
return arg1 .. arg2
@ -121,7 +121,7 @@ fn test_lua_multi() {
fn test_coercion() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
int = 123
str = "123"
@ -158,7 +158,7 @@ fn test_error() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function no_error()
end
@ -245,7 +245,7 @@ fn test_error() {
assert!(return_string_error.call::<_, Error>(()).is_ok());
match lua.eval::<()>("if youre happy and you know it syntax error", None) {
match lua.eval::<_, ()>("if youre happy and you know it syntax error", None) {
Err(Error::SyntaxError {
incomplete_input: false,
..
@ -253,7 +253,7 @@ fn test_error() {
Err(_) => panic!("error is not LuaSyntaxError::Syntax kind"),
_ => panic!("error not returned"),
}
match lua.eval::<()>("function i_will_finish_what_i()", None) {
match lua.eval::<_, ()>("function i_will_finish_what_i()", None) {
Err(Error::SyntaxError {
incomplete_input: true,
..
@ -270,7 +270,7 @@ fn test_error() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function rust_panic()
pcall(function () rust_panic_function() end)
@ -296,7 +296,7 @@ fn test_error() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function rust_panic()
xpcall(function() rust_panic_function() end, function() end)
@ -337,7 +337,7 @@ fn test_result_conversions() {
globals.set("err", err).unwrap();
globals.set("ok", ok).unwrap();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
local r, e = err()
assert(r == nil)
@ -381,19 +381,19 @@ fn test_num_conversion() {
Some(1.5)
);
assert_eq!(lua.eval::<i64>("1.0", None).unwrap(), 1);
assert_eq!(lua.eval::<f64>("1.0", None).unwrap(), 1.0);
assert_eq!(lua.eval::<String>("1.0", None).unwrap(), "1.0");
assert_eq!(lua.eval::<_, i64>("1.0", None).unwrap(), 1);
assert_eq!(lua.eval::<_, f64>("1.0", None).unwrap(), 1.0);
assert_eq!(lua.eval::<_, String>("1.0", None).unwrap(), "1.0");
assert_eq!(lua.eval::<i64>("1.5", None).unwrap(), 1);
assert_eq!(lua.eval::<f64>("1.5", None).unwrap(), 1.5);
assert_eq!(lua.eval::<String>("1.5", None).unwrap(), "1.5");
assert_eq!(lua.eval::<_, i64>("1.5", None).unwrap(), 1);
assert_eq!(lua.eval::<_, f64>("1.5", None).unwrap(), 1.5);
assert_eq!(lua.eval::<_, String>("1.5", None).unwrap(), "1.5");
assert!(lua.eval::<u64>("-1", None).is_err());
assert_eq!(lua.eval::<i64>("-1", None).unwrap(), -1);
assert!(lua.eval::<_, u64>("-1", None).is_err());
assert_eq!(lua.eval::<_, i64>("-1", None).unwrap(), -1);
assert!(lua.unpack::<u64>(lua.pack(1u128 << 64).unwrap()).is_err());
assert!(lua.eval::<i64>("math.huge", None).is_err());
assert!(lua.eval::<_, i64>("math.huge", None).is_err());
assert_eq!(
lua.unpack::<f64>(lua.pack(f32::MAX).unwrap()).unwrap(),
@ -414,27 +414,27 @@ fn test_pcall_xpcall() {
// make sure that we handle not enough arguments
assert!(lua.exec::<()>("pcall()", None).is_err());
assert!(lua.exec::<()>("xpcall()", None).is_err());
assert!(lua.exec::<()>("xpcall(function() end)", None).is_err());
assert!(lua.exec::<_, ()>("pcall()", None).is_err());
assert!(lua.exec::<_, ()>("xpcall()", None).is_err());
assert!(lua.exec::<_, ()>("xpcall(function() end)", None).is_err());
// Make sure that the return values from are correct on success
let (r, e) = lua
.eval::<(bool, String)>("pcall(function(p) return p end, 'foo')", None)
.eval::<_, (bool, String)>("pcall(function(p) return p end, 'foo')", None)
.unwrap();
assert!(r);
assert_eq!(e, "foo");
let (r, e) = lua
.eval::<(bool, String)>("xpcall(function(p) return p end, print, 'foo')", None)
.eval::<_, (bool, String)>("xpcall(function(p) return p end, print, 'foo')", None)
.unwrap();
assert!(r);
assert_eq!(e, "foo");
// Make sure that the return values are correct on errors, and that error handling works
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
pcall_error = nil
pcall_status, pcall_error = pcall(error, "testerror")
@ -458,7 +458,7 @@ fn test_pcall_xpcall() {
);
// Make sure that weird xpcall error recursion at least doesn't cause unsafety or panics.
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function xpcall_recursion()
xpcall(error, function(err) error(err) end, "testerror")
@ -515,7 +515,7 @@ fn test_recursive_mut_callback_error() {
#[test]
fn test_set_metatable_nil() {
let lua = Lua::new();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
a = {}
setmetatable(a, nil)
@ -527,7 +527,7 @@ fn test_set_metatable_nil() {
#[test]
fn test_gc_error() {
let lua = Lua::new();
match lua.exec::<()>(
match lua.exec::<_, ()>(
r#"
val = nil
table = {}
@ -602,7 +602,7 @@ fn test_drop_registry_value() {
drop(r);
lua.expire_registry_values();
lua.exec::<()>(r#"collectgarbage("collect")"#, None)
lua.exec::<_, ()>(r#"collectgarbage("collect")"#, None)
.unwrap();
assert_eq!(Arc::strong_count(&rc), 1);
@ -658,7 +658,7 @@ fn too_many_returns() {
#[test]
fn too_many_arguments() {
let lua = Lua::new();
lua.exec::<()>("function test(...) end", None).unwrap();
lua.exec::<_, ()>("function test(...) end", None).unwrap();
let args = Variadic::from_iter(1..1000000);
assert!(
lua.globals()
@ -691,7 +691,7 @@ fn too_many_recursions() {
fn too_many_binds() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function f(...)
end

View file

@ -9,7 +9,7 @@ fn test_thread() {
let lua = Lua::new();
let thread = lua
.create_thread(
lua.eval::<Function>(
lua.eval::<_, Function>(
r#"
function (s)
local sum = s
@ -37,7 +37,7 @@ fn test_thread() {
let accumulate = lua
.create_thread(
lua.eval::<Function>(
lua.eval::<_, Function>(
r#"
function (sum)
while true do
@ -58,7 +58,7 @@ fn test_thread() {
assert_eq!(accumulate.status(), ThreadStatus::Error);
let thread = lua
.eval::<Thread>(
.eval::<_, Thread>(
r#"
coroutine.create(function ()
while true do

View file

@ -8,7 +8,7 @@ use rlua::{Function, LightUserData, Lua};
fn test_lightuserdata() {
let lua = Lua::new();
let globals = lua.globals();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function id(a)
return a

View file

@ -46,7 +46,7 @@ fn test_methods() {
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42)).unwrap();
globals.set("userdata", userdata.clone()).unwrap();
lua.exec::<()>(
lua.exec::<_, ()>(
r#"
function get_it()
return userdata:get_value()
@ -98,20 +98,20 @@ fn test_metamethods() {
globals.set("userdata1", MyUserData(7)).unwrap();
globals.set("userdata2", MyUserData(3)).unwrap();
assert_eq!(
lua.eval::<MyUserData>("userdata1 + userdata2", None)
lua.eval::<_, MyUserData>("userdata1 + userdata2", None)
.unwrap()
.0,
10
);
assert_eq!(
lua.eval::<MyUserData>("userdata1 - userdata2", None)
lua.eval::<_, MyUserData>("userdata1 - userdata2", None)
.unwrap()
.0,
4
);
assert_eq!(lua.eval::<i64>("userdata1:get()", None).unwrap(), 7);
assert_eq!(lua.eval::<i64>("userdata2.inner", None).unwrap(), 3);
assert!(lua.eval::<()>("userdata2.nonexist_field", None).is_err());
assert_eq!(lua.eval::<_, i64>("userdata1:get()", None).unwrap(), 7);
assert_eq!(lua.eval::<_, i64>("userdata2.inner", None).unwrap(), 3);
assert!(lua.eval::<_, ()>("userdata2.nonexist_field", None).is_err());
}
#[test]
@ -136,7 +136,7 @@ fn test_gc_userdata() {
}
assert!(
lua.eval::<()>(
lua.eval::<_, ()>(
r#"
local tbl = setmetatable({
userdata = userdata