diff --git a/examples/guided_tour.rs b/examples/guided_tour.rs index ddc6d1f..9cbe786 100644 --- a/examples/guided_tour.rs +++ b/examples/guided_tour.rs @@ -30,7 +30,7 @@ fn main() -> Result<()> { global = 'foo'..'bar' "#, ) - .set_name("example code")? + .set_name("example code") .exec()?; assert_eq!(globals.get::<_, String>("global")?, "foobar"); diff --git a/mlua_derive/src/lib.rs b/mlua_derive/src/lib.rs index 7931dc0..2346e2d 100644 --- a/mlua_derive/src/lib.rs +++ b/mlua_derive/src/lib.rs @@ -98,37 +98,36 @@ pub fn chunk(input: TokenStream) -> TokenStream { use ::mlua::{AsChunk, ChunkMode, Lua, Result, Value}; use ::std::borrow::Cow; use ::std::io::Result as IoResult; - use ::std::marker::PhantomData; use ::std::sync::Mutex; - fn annotate<'a, F: FnOnce(&'a Lua) -> Result>>(f: F) -> F { f } + struct InnerChunk FnOnce(&'a Lua) -> Result>>(Mutex>); - struct InnerChunk<'a, F: FnOnce(&'a Lua) -> Result>>(Mutex>, PhantomData<&'a ()>); - - impl<'lua, F> AsChunk<'lua> for InnerChunk<'lua, F> + impl AsChunk<'static> for InnerChunk where - F: FnOnce(&'lua Lua) -> Result>, + F: for <'a> FnOnce(&'a Lua) -> Result>, { - fn source(&self) -> IoResult> { - Ok(Cow::Borrowed((#source).as_bytes())) - } - - fn env(&self, lua: &'lua Lua) -> Result>> { + fn env<'lua>(&self, lua: &'lua Lua) -> Result> { if #caps_len > 0 { if let Ok(mut make_env) = self.0.lock() { if let Some(make_env) = make_env.take() { - return make_env(lua).map(Some); + return make_env(lua); } } } - Ok(None) + Ok(Value::Nil) } fn mode(&self) -> Option { Some(ChunkMode::Text) } + + fn source(self) -> IoResult> { + Ok(Cow::Borrowed((#source).as_bytes())) + } } + fn annotate FnOnce(&'a Lua) -> Result>>(f: F) -> F { f } + let make_env = annotate(move |lua: &Lua| -> Result { let globals = lua.globals(); let env = lua.create_table()?; @@ -143,7 +142,7 @@ pub fn chunk(input: TokenStream) -> TokenStream { Ok(Value::Table(env)) }); - &InnerChunk(Mutex::new(Some(make_env)), PhantomData) + InnerChunk(Mutex::new(Some(make_env))) }}; wrapped_code.into() diff --git a/src/chunk.rs b/src/chunk.rs index bd24ae4..0315ef9 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -18,10 +18,7 @@ use {futures_core::future::LocalBoxFuture, futures_util::future}; /// /// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2 /// [`Chunk`]: crate::Chunk -pub trait AsChunk<'lua> { - /// Returns chunk data (can be text or binary) - fn source(&self) -> IoResult>; - +pub trait AsChunk<'a> { /// Returns optional chunk name fn name(&self) -> Option { None @@ -30,58 +27,74 @@ pub trait AsChunk<'lua> { /// Returns optional chunk [environment] /// /// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2 - fn env(&self, _lua: &'lua Lua) -> Result>> { - Ok(None) + fn env<'lua>(&self, lua: &'lua Lua) -> Result> { + let _lua = lua; // suppress warning + Ok(Value::Nil) } /// Returns optional chunk mode (text or binary) fn mode(&self) -> Option { None } + + /// Returns chunk data (can be text or binary) + fn source(self) -> IoResult>; } -impl<'lua> AsChunk<'lua> for str { - fn source(&self) -> IoResult> { +impl<'a> AsChunk<'a> for &'a str { + fn source(self) -> IoResult> { Ok(Cow::Borrowed(self.as_ref())) } } -impl<'lua> AsChunk<'lua> for StdString { - fn source(&self) -> IoResult> { +impl AsChunk<'static> for StdString { + fn source(self) -> IoResult> { + Ok(Cow::Owned(self.into_bytes())) + } +} + +impl<'a> AsChunk<'a> for &'a StdString { + fn source(self) -> IoResult> { + Ok(Cow::Borrowed(self.as_bytes())) + } +} + +impl<'a> AsChunk<'a> for &'a [u8] { + fn source(self) -> IoResult> { + Ok(Cow::Borrowed(self)) + } +} + +impl AsChunk<'static> for Vec { + fn source(self) -> IoResult> { + Ok(Cow::Owned(self)) + } +} + +impl<'a> AsChunk<'a> for &'a Vec { + fn source(self) -> IoResult> { Ok(Cow::Borrowed(self.as_ref())) } } -impl<'lua> AsChunk<'lua> for [u8] { - fn source(&self) -> IoResult> { - Ok(Cow::Borrowed(self)) - } -} - -impl<'lua> AsChunk<'lua> for Vec { - fn source(&self) -> IoResult> { - Ok(Cow::Borrowed(self)) - } -} - -impl<'lua> AsChunk<'lua> for Path { - fn source(&self) -> IoResult> { - std::fs::read(self).map(Cow::Owned) - } - +impl AsChunk<'static> for &Path { fn name(&self) -> Option { Some(format!("@{}", self.display())) } -} -impl<'lua> AsChunk<'lua> for PathBuf { - fn source(&self) -> IoResult> { + fn source(self) -> IoResult> { std::fs::read(self).map(Cow::Owned) } +} +impl AsChunk<'static> for PathBuf { fn name(&self) -> Option { Some(format!("@{}", self.display())) } + + fn source(self) -> IoResult> { + std::fs::read(self).map(Cow::Owned) + } } /// Returned from [`Lua::load`] and is used to finalize loading and executing Lua main chunks. @@ -90,10 +103,10 @@ impl<'lua> AsChunk<'lua> for PathBuf { #[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"] pub struct Chunk<'lua, 'a> { pub(crate) lua: &'lua Lua, - pub(crate) source: IoResult>, - pub(crate) name: Option, - pub(crate) env: Result>>, + pub(crate) name: StdString, + pub(crate) env: Result>, pub(crate) mode: Option, + pub(crate) source: IoResult>, #[cfg(feature = "luau")] pub(crate) compiler: Option, } @@ -237,11 +250,9 @@ impl Compiler { impl<'lua, 'a> Chunk<'lua, 'a> { /// Sets the name of this chunk, which results in more informative error traces. - pub fn set_name(mut self, name: impl AsRef) -> Result { - self.name = Some(name.as_ref().to_string()); - // Do extra validation - let _ = self.convert_name()?; - Ok(self) + pub fn set_name(mut self, name: impl Into) -> Self { + self.name = name.into(); + self } /// Sets the first upvalue (`_ENV`) of the loaded chunk to the given value. @@ -255,10 +266,9 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// All global variables (including the standard library!) are looked up in `_ENV`, so it may be /// necessary to populate the environment in order for scripts using custom environments to be /// useful. - pub fn set_environment>(mut self, env: V) -> Result { - // Prefer to propagate errors here and wrap to `Ok` - self.env = Ok(Some(env.to_lua(self.lua)?)); - Ok(self) + pub fn set_environment>(mut self, env: V) -> Self { + self.env = env.to_lua(self.lua); + self } /// Sets whether the chunk is text or binary (autodetected by default). @@ -299,10 +309,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// [`exec`]: #method.exec #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn exec_async<'fut>(self) -> LocalBoxFuture<'fut, Result<()>> - where - 'lua: 'fut, - { + pub fn exec_async(self) -> LocalBoxFuture<'lua, Result<()>> { self.call_async(()) } @@ -387,9 +394,9 @@ impl<'lua, 'a> Chunk<'lua, 'a> { self.compile(); } - let name = self.convert_name()?; + let name = Self::convert_name(self.name)?; self.lua - .load_chunk(self.source?.as_ref(), name.as_deref(), self.env?, self.mode) + .load_chunk(Some(&name), self.env?, self.mode, self.source?.as_ref()) } /// Compiles the chunk and changes mode to binary. @@ -408,7 +415,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { self.mode = Some(ChunkMode::Binary); } #[cfg(not(feature = "luau"))] - if let Ok(func) = self.lua.load_chunk(source.as_ref(), None, None, None) { + if let Ok(func) = self.lua.load_chunk(None, Value::Nil, None, source.as_ref()) { let data = func.dump(false); self.source = Ok(Cow::Owned(data)); self.mode = Some(ChunkMode::Binary); @@ -470,9 +477,9 @@ impl<'lua, 'a> Chunk<'lua, 'a> { .map(|c| c.compile(&source)) .unwrap_or(source); - let name = self.convert_name()?; + let name = Self::convert_name(self.name.clone())?; self.lua - .load_chunk(&source, name.as_deref(), self.env.clone()?, None) + .load_chunk(Some(&name), self.env.clone()?, None, &source) } fn detect_mode(&self) -> ChunkMode { @@ -493,12 +500,8 @@ impl<'lua, 'a> Chunk<'lua, 'a> { } } - fn convert_name(&self) -> Result> { - self.name - .clone() - .map(CString::new) - .transpose() - .map_err(|err| Error::RuntimeError(format!("invalid name: {err}"))) + fn convert_name(name: String) -> Result { + CString::new(name).map_err(|err| Error::RuntimeError(format!("invalid name: {err}"))) } fn expression_source(source: &[u8]) -> Vec { diff --git a/src/function.rs b/src/function.rs index d5edda4..0581e92 100644 --- a/src/function.rs +++ b/src/function.rs @@ -255,7 +255,7 @@ impl<'lua> Function<'lua> { "#, ) .try_cache() - .set_name("_mlua_bind")? + .set_name("_mlua_bind") .call((self.clone(), args_wrapper)) } diff --git a/src/lua.rs b/src/lua.rs index 86473eb..e22b8d7 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1348,19 +1348,14 @@ impl Lua { /// /// [`Chunk::exec`]: crate::Chunk::exec #[track_caller] - pub fn load<'lua, 'a, S>(&'lua self, chunk: &'a S) -> Chunk<'lua, 'a> - where - S: AsChunk<'lua> + ?Sized, - { + pub fn load<'lua, 'a>(&'lua self, chunk: impl AsChunk<'a>) -> Chunk<'lua, 'a> { let caller = Location::caller(); - let name = chunk.name().unwrap_or_else(|| caller.to_string()); - Chunk { lua: self, - source: chunk.source(), - name: Some(name), + name: chunk.name().unwrap_or_else(|| caller.to_string()), env: chunk.env(self), mode: chunk.mode(), + source: chunk.source(), #[cfg(feature = "luau")] compiler: unsafe { (*self.extra.get()).compiler.clone() }, } @@ -1368,10 +1363,10 @@ impl Lua { pub(crate) fn load_chunk<'lua>( &'lua self, - source: &[u8], name: Option<&CStr>, - env: Option>, + env: Value<'lua>, mode: Option, + source: &[u8], ) -> Result> { let state = self.state(); unsafe { @@ -1392,7 +1387,7 @@ impl Lua { mode_str, ) { ffi::LUA_OK => { - if let Some(env) = env { + if env != Value::Nil { self.push_value(env)?; #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] ffi::lua_setupvalue(state, -2, 1); @@ -2885,8 +2880,8 @@ impl Lua { "#, ) .try_cache() - .set_name("_mlua_async_poll")? - .set_environment(env)? + .set_name("_mlua_async_poll") + .set_environment(env) .into_function() } diff --git a/src/luau.rs b/src/luau.rs index 7dab235..807a7f1 100644 --- a/src/luau.rs +++ b/src/luau.rs @@ -106,7 +106,7 @@ fn lua_require(lua: &Lua, name: Option) -> Result { let value = lua .load(&source) - .set_name(&format!("={}", source_name))? + .set_name(&format!("={}", source_name)) .set_mode(ChunkMode::Text) .call::<_, Value>(())?; diff --git a/tests/async.rs b/tests/async.rs index 186e0d1..fc7a631 100644 --- a/tests/async.rs +++ b/tests/async.rs @@ -439,7 +439,7 @@ async fn test_async_thread_error() -> Result<()> { let lua = Lua::new(); let result = lua .load("function x(...) error(...) end x(...)") - .set_name("chunk")? + .set_name("chunk") .call_async::<_, ()>(MyUserData) .await; assert!( diff --git a/tests/chunk.rs b/tests/chunk.rs index 4f87d60..1a26c3c 100644 --- a/tests/chunk.rs +++ b/tests/chunk.rs @@ -14,10 +14,10 @@ fn test_chunk_path() -> Result<()> { return 321 "#, )?; - let i: i32 = lua.load(&temp_dir.path().join("module.lua")).eval()?; + let i: i32 = lua.load(&*temp_dir.path().join("module.lua")).eval()?; assert_eq!(i, 321); - match lua.load(&temp_dir.path().join("module2.lua")).exec() { + match lua.load(&*temp_dir.path().join("module2.lua")).exec() { Err(Error::ExternalError(err)) if err.downcast_ref::().unwrap().kind() == io::ErrorKind::NotFound => {} res => panic!("expected io::Error, got {:?}", res), diff --git a/tests/function.rs b/tests/function.rs index 6f20ff3..6d4848b 100644 --- a/tests/function.rs +++ b/tests/function.rs @@ -126,7 +126,7 @@ fn test_function_info() -> Result<()> { end "#, ) - .set_name("source1")? + .set_name("source1") .exec()?; let function1 = globals.get::<_, Function>("function1")?; diff --git a/tests/tests.rs b/tests/tests.rs index 619ef1b..e783392 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1072,7 +1072,7 @@ fn test_chunk_env() -> Result<()> { test_var = 1 "#, ) - .set_environment(env1.clone())? + .set_environment(env1.clone()) .exec()?; lua.load( @@ -1081,18 +1081,11 @@ fn test_chunk_env() -> Result<()> { test_var = 2 "#, ) - .set_environment(env2.clone())? + .set_environment(env2.clone()) .exec()?; - assert_eq!( - lua.load("test_var").set_environment(env1)?.eval::()?, - 1 - ); - - assert_eq!( - lua.load("test_var").set_environment(env2)?.eval::()?, - 2 - ); + assert_eq!(lua.load("test_var").set_environment(env1).eval::()?, 1); + assert_eq!(lua.load("test_var").set_environment(env2).eval::()?, 2); Ok(()) } @@ -1227,7 +1220,7 @@ fn test_inspect_stack() -> Result<()> { assert(logline("world") == '[string "chunk"]:12 world') "#, ) - .set_name("chunk")? + .set_name("chunk") .exec()?; Ok(())