summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2022-03-01 12:29:43 +0000
committerAlex Orlenko <zxteam@protonmail.com>2022-03-21 01:08:47 +0000
commit32124b31a05a25c0146864661f3a34a8abb1a7d6 (patch)
treeea34992510c0553a434793b01abcfa37db5e288c /src
parent3e5f8e7bb8bb2822629593ecbd316f0fda7b4de8 (diff)
downloadmlua-32124b31a05a25c0146864661f3a34a8abb1a7d6.zip
Move chunks structs to a new module.
Add Luau Compiler interface to compile sources.
Diffstat (limited to 'src')
-rw-r--r--src/chunk.rs397
-rw-r--r--src/ffi/luau/compat.rs2
-rw-r--r--src/ffi/luau/luacode.rs21
-rw-r--r--src/lib.rs7
-rw-r--r--src/lua.rs227
5 files changed, 429 insertions, 225 deletions
diff --git a/src/chunk.rs b/src/chunk.rs
new file mode 100644
index 0000000..3bb7c18
--- /dev/null
+++ b/src/chunk.rs
@@ -0,0 +1,397 @@
+use std::borrow::Cow;
+use std::ffi::CString;
+
+use crate::error::{Error, Result};
+use crate::ffi;
+use crate::function::Function;
+use crate::lua::Lua;
+use crate::value::{FromLuaMulti, ToLua, ToLuaMulti, Value};
+
+#[cfg(feature = "async")]
+use {futures_core::future::LocalBoxFuture, futures_util::future};
+
+/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
+///
+/// [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) -> &[u8];
+
+ /// Returns optional chunk name
+ fn name(&self) -> Option<CString> {
+ None
+ }
+
+ /// Returns optional chunk [environment]
+ ///
+ /// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2
+ fn env(&self, _lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
+ Ok(None)
+ }
+
+ /// Returns optional chunk mode (text or binary)
+ fn mode(&self) -> Option<ChunkMode> {
+ None
+ }
+}
+
+impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
+ fn source(&self) -> &[u8] {
+ self.as_ref()
+ }
+}
+
+/// Returned from [`Lua::load`] and is used to finalize loading and executing Lua main chunks.
+///
+/// [`Lua::load`]: crate::Lua::load
+#[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: Cow<'a, [u8]>,
+ pub(crate) name: Option<CString>,
+ pub(crate) env: Result<Option<Value<'lua>>>,
+ pub(crate) mode: Option<ChunkMode>,
+ #[cfg(feature = "luau")]
+ pub(crate) compiler: Option<Compiler>,
+}
+
+/// Represents chunk mode (text or binary).
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ChunkMode {
+ Text,
+ Binary,
+}
+
+/// Luau compiler
+#[cfg(feature = "luau")]
+#[derive(Clone, Copy, Debug)]
+pub struct Compiler {
+ optimization_level: u8,
+ debug_level: u8,
+ coverage_level: u8,
+}
+
+#[cfg(feature = "luau")]
+impl Default for Compiler {
+ fn default() -> Self {
+ // Defaults are taken from luacode.h
+ Compiler {
+ optimization_level: 1,
+ debug_level: 1,
+ coverage_level: 0,
+ }
+ }
+}
+
+#[cfg(feature = "luau")]
+impl Compiler {
+ /// Creates Luau compiler instance with default options
+ pub fn new() -> Self {
+ Compiler::default()
+ }
+
+ /// Sets Luau compiler optimization level.
+ ///
+ /// Possible values:
+ /// 0 - no optimization
+ /// 1 - baseline optimization level that doesn't prevent debuggability (default)
+ /// 2 - includes optimizations that harm debuggability such as inlining
+ #[cfg(feature = "luau")]
+ pub fn set_optimization_level(mut self, level: u8) -> Self {
+ self.optimization_level = level;
+ self
+ }
+
+ /// Sets Luau compiler debug level.
+ ///
+ /// Possible values:
+ /// 0 - no debugging support
+ /// 1 - line info & function names only; sufficient for backtraces (default)
+ /// 2 - full debug info with local & upvalue names; necessary for debugger
+ #[cfg(feature = "luau")]
+ pub fn set_debug_level(mut self, level: u8) -> Self {
+ self.debug_level = level;
+ self
+ }
+
+ /// Sets Luau compiler code coverage level.
+ ///
+ /// Possible values:
+ /// 0 - no code coverage support (default)
+ /// 1 - statement coverage
+ /// 2 - statement and expression coverage (verbose)
+ #[cfg(feature = "luau")]
+ pub fn set_coverage_level(mut self, level: u8) -> Self {
+ self.coverage_level = level;
+ self
+ }
+
+ /// Compiles the `source` into bytecode.
+ pub fn compile(&self, source: impl AsRef<[u8]>) -> Vec<u8> {
+ use std::os::raw::c_int;
+ use std::ptr;
+
+ unsafe {
+ let options = ffi::lua_CompileOptions {
+ optimizationLevel: self.optimization_level as c_int,
+ debugLevel: self.debug_level as c_int,
+ coverageLevel: self.coverage_level as c_int,
+ vectorLib: ptr::null(),
+ vectorCtor: ptr::null(),
+ mutableGlobals: ptr::null_mut(),
+ };
+ ffi::luau_compile(source.as_ref(), options)
+ }
+ }
+}
+
+impl<'lua, 'a> Chunk<'lua, 'a> {
+ /// Sets the name of this chunk, which results in more informative error traces.
+ pub fn set_name<S: AsRef<[u8]> + ?Sized>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
+ let name =
+ CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
+ from: "&str",
+ to: "string",
+ message: Some(e.to_string()),
+ })?;
+ self.name = Some(name);
+ Ok(self)
+ }
+
+ /// Sets the first upvalue (`_ENV`) of the loaded chunk to the given value.
+ ///
+ /// Lua main chunks always have exactly one upvalue, and this upvalue is used as the `_ENV`
+ /// variable inside the chunk. By default this value is set to the global environment.
+ ///
+ /// Calling this method changes the `_ENV` upvalue to the value provided, and variables inside
+ /// the chunk will refer to the given environment rather than the global one.
+ ///
+ /// 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<V: ToLua<'lua>>(mut self, env: V) -> Result<Chunk<'lua, 'a>> {
+ // Prefer to propagate errors here and wrap to `Ok`
+ self.env = Ok(Some(env.to_lua(self.lua)?));
+ Ok(self)
+ }
+
+ /// Sets whether the chunk is text or binary (autodetected by default).
+ ///
+ /// Be aware, Lua does not check the consistency of the code inside binary chunks.
+ /// Running maliciously crafted bytecode can crash the interpreter.
+ pub fn set_mode(mut self, mode: ChunkMode) -> Chunk<'lua, 'a> {
+ self.mode = Some(mode);
+ self
+ }
+
+ /// Sets Luau compiler optimization level.
+ ///
+ /// See [`Compiler::set_optimization_level`] for details.
+ ///
+ /// Requires `feature = "luau`
+ #[cfg(feature = "luau")]
+ pub fn set_optimization_level(mut self, level: u8) -> Self {
+ self.compiler
+ .get_or_insert_with(Default::default)
+ .set_optimization_level(level);
+ self
+ }
+
+ /// Sets Luau compiler debug level.
+ ///
+ /// See [`Compiler::set_debug_level`] for details.
+ ///
+ /// Requires `feature = "luau`
+ #[cfg(feature = "luau")]
+ pub fn set_debug_level(mut self, level: u8) -> Self {
+ self.compiler
+ .get_or_insert_with(Default::default)
+ .set_debug_level(level);
+ self
+ }
+
+ /// Sets Luau compiler code coverage level.
+ ///
+ /// See [`Compiler::set_coverage_level`] for details.
+ ///
+ /// Requires `feature = "luau`
+ #[cfg(feature = "luau")]
+ pub fn set_coverage_level(mut self, level: u8) -> Self {
+ self.compiler
+ .get_or_insert_with(Default::default)
+ .set_coverage_level(level);
+ self
+ }
+
+ /// Compiles the chunk and changes mode to binary.
+ ///
+ /// It does nothing if the chunk is already binary.
+ #[cfg(feature = "luau")]
+ #[doc(hidden)]
+ pub fn compile(mut self) -> Self {
+ if self.detect_mode() == ChunkMode::Text {
+ let data = self
+ .compiler
+ .unwrap_or_default()
+ .compile(self.source.as_ref());
+ self.mode = Some(ChunkMode::Binary);
+ self.source = Cow::Owned(data);
+ }
+ self
+ }
+
+ /// Execute this chunk of code.
+ ///
+ /// This is equivalent to calling the chunk function with no arguments and no return values.
+ pub fn exec(self) -> Result<()> {
+ self.call(())?;
+ Ok(())
+ }
+
+ /// Asynchronously execute this chunk of code.
+ ///
+ /// See [`exec`] for more details.
+ ///
+ /// Requires `feature = "async"`
+ ///
+ /// [`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,
+ {
+ self.call_async(())
+ }
+
+ /// Evaluate the chunk as either an expression or block.
+ ///
+ /// If the chunk can be parsed as an expression, this loads and executes the chunk and returns
+ /// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
+ /// and this is equivalent to calling `exec`.
+ pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
+ // Bytecode is always interpreted as a statement.
+ // For source code, 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.
+ if self.detect_mode() == ChunkMode::Binary {
+ self.call(())
+ } else if let Ok(function) = self.to_expression() {
+ function.call(())
+ } else {
+ self.call(())
+ }
+ }
+
+ /// Asynchronously evaluate the chunk as either an expression or block.
+ ///
+ /// See [`eval`] for more details.
+ ///
+ /// Requires `feature = "async"`
+ ///
+ /// [`eval`]: #method.eval
+ #[cfg(feature = "async")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
+ pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result<R>>
+ where
+ 'lua: 'fut,
+ R: FromLuaMulti<'lua> + 'fut,
+ {
+ if self.detect_mode() == ChunkMode::Binary {
+ self.call_async(())
+ } else if let Ok(function) = self.to_expression() {
+ function.call_async(())
+ } else {
+ self.call_async(())
+ }
+ }
+
+ /// Load the chunk function and call it with the given arguments.
+ ///
+ /// This is equivalent to `into_function` and calling the resulting function.
+ pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(self, args: A) -> Result<R> {
+ self.into_function()?.call(args)
+ }
+
+ /// Load the chunk function and asynchronously call it with the given arguments.
+ ///
+ /// See [`call`] for more details.
+ ///
+ /// Requires `feature = "async"`
+ ///
+ /// [`call`]: #method.call
+ #[cfg(feature = "async")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
+ pub fn call_async<'fut, A, R>(self, args: A) -> LocalBoxFuture<'fut, Result<R>>
+ where
+ 'lua: 'fut,
+ A: ToLuaMulti<'lua>,
+ R: FromLuaMulti<'lua> + 'fut,
+ {
+ match self.into_function() {
+ Ok(func) => func.call_async(args),
+ Err(e) => Box::pin(future::err(e)),
+ }
+ }
+
+ /// Load this chunk into a regular `Function`.
+ ///
+ /// This simply compiles the chunk without actually executing it.
+ pub fn into_function(self) -> Result<Function<'lua>> {
+ #[cfg(not(feature = "luau"))]
+ let self_ = self;
+ #[cfg(feature = "luau")]
+ let self_ = match self.compiler {
+ // We don't need to compile source if no compiler options set
+ Some(_) => self.compile(),
+ _ => self,
+ };
+
+ self_.lua.load_chunk(
+ self_.source.as_ref(),
+ self_.name.as_ref(),
+ self_.env()?,
+ self_.mode,
+ )
+ }
+
+ fn env(&self) -> Result<Option<Value<'lua>>> {
+ self.env.clone()
+ }
+
+ fn expression_source(&self) -> Vec<u8> {
+ let mut buf = Vec::with_capacity(b"return ".len() + self.source.len());
+ buf.extend(b"return ");
+ buf.extend(self.source.as_ref());
+ buf
+ }
+
+ fn to_expression(&self) -> Result<Function<'lua>> {
+ // We assume that mode is Text
+ let source = self.expression_source();
+ // We don't need to compile source if no compiler options set
+ #[cfg(feature = "luau")]
+ let source = self.compiler.map(|c| c.compile(&source)).unwrap_or(source);
+
+ self.lua
+ .load_chunk(&source, self.name.as_ref(), self.env()?, None)
+ }
+
+ fn detect_mode(&self) -> ChunkMode {
+ match self.mode {
+ Some(mode) => mode,
+ None => {
+ #[cfg(not(feature = "luau"))]
+ if self.source.starts_with(ffi::LUA_SIGNATURE) {
+ return ChunkMode::Binary;
+ }
+ #[cfg(feature = "luau")]
+ if self.source[0] < b'\n' {
+ return ChunkMode::Binary;
+ }
+ ChunkMode::Text
+ }
+ }
+ }
+}
diff --git a/src/ffi/luau/compat.rs b/src/ffi/luau/compat.rs
index 9094822..db9c55c 100644
--- a/src/ffi/luau/compat.rs
+++ b/src/ffi/luau/compat.rs
@@ -380,7 +380,7 @@ pub unsafe fn luaL_loadbufferx(
}
if chunk_is_text {
- let data = luau_compile(data, size, ptr::null_mut(), &mut size);
+ let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
let ok = luau_load(L, name, data, size, 0) == 0;
free(data as *mut c_void);
if !ok {
diff --git a/src/ffi/luau/luacode.rs b/src/ffi/luau/luacode.rs
index 3f24b65..571db4c 100644
--- a/src/ffi/luau/luacode.rs
+++ b/src/ffi/luau/luacode.rs
@@ -1,6 +1,7 @@
//! Contains definitions from `luacode.h`.
-use std::os::raw::{c_char, c_int};
+use std::os::raw::{c_char, c_int, c_void};
+use std::slice;
#[repr(C)]
pub struct lua_CompileOptions {
@@ -13,10 +14,26 @@ pub struct lua_CompileOptions {
}
extern "C" {
- pub fn luau_compile(
+ #[link_name = "luau_compile"]
+ pub fn luau_compile_(
source: *const c_char,
size: usize,
options: *mut lua_CompileOptions,
outsize: *mut usize,
) -> *mut c_char;
+
+ fn free(p: *mut c_void);
+}
+
+pub unsafe fn luau_compile(source: &[u8], mut options: lua_CompileOptions) -> Vec<u8> {
+ let mut outsize = 0;
+ let data_ptr = luau_compile_(
+ source.as_ptr() as *const c_char,
+ source.len(),
+ &mut options,
+ &mut outsize,
+ );
+ let data = slice::from_raw_parts(data_ptr as *mut u8, outsize).to_vec();
+ free(data_ptr as *mut c_void);
+ data
}
diff --git a/src/lib.rs b/src/lib.rs
index 57e45b0..dbae8ae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -81,6 +81,7 @@
#[macro_use]
mod macros;
+mod chunk;
mod conversion;
mod error;
mod ffi;
@@ -102,10 +103,11 @@ pub mod prelude;
pub use crate::{ffi::lua_CFunction, ffi::lua_State};
+pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
pub use crate::function::Function;
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
-pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions};
+pub use crate::lua::{GCMode, Lua, LuaOptions};
pub use crate::multi::Variadic;
pub use crate::scope::Scope;
pub use crate::stdlib::StdLib;
@@ -121,6 +123,9 @@ pub use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti
#[cfg(not(feature = "luau"))]
pub use crate::hook::HookTriggers;
+#[cfg(feature = "luau")]
+pub use crate::chunk::Compiler;
+
#[cfg(feature = "async")]
pub use crate::thread::AsyncThread;
diff --git a/src/lua.rs b/src/lua.rs
index 8a4475c..aed086a 100644
--- a/src/lua.rs
+++ b/src/lua.rs
@@ -1,4 +1,5 @@
use std::any::{Any, TypeId};
+use std::borrow::Cow;
use std::cell::{Ref, RefCell, RefMut, UnsafeCell};
use std::collections::HashMap;
use std::ffi::CString;
@@ -11,6 +12,7 @@ use std::{mem, ptr, str};
use rustc_hash::FxHashMap;
+use crate::chunk::{AsChunk, Chunk, ChunkMode};
use crate::error::{Error, Result};
use crate::ffi;
use crate::function::Function;
@@ -1145,17 +1147,19 @@ impl Lua {
{
Chunk {
lua: self,
- source: source.source(),
+ source: Cow::Borrowed(source.source()),
name: match source.name() {
Some(name) => Some(name),
None => CString::new(Location::caller().to_string()).ok(),
},
env: source.env(self),
mode: source.mode(),
+ #[cfg(feature = "luau")]
+ compiler: None,
}
}
- fn load_chunk<'lua>(
+ pub(crate) fn load_chunk<'lua>(
&'lua self,
source: &[u8],
name: Option<&CString>,
@@ -2705,225 +2709,6 @@ impl Lua {
}
}
-/// Returned from [`Lua::load`] and is used to finalize loading and executing Lua main chunks.
-///
-/// [`Lua::load`]: crate::Lua::load
-#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
-pub struct Chunk<'lua, 'a> {
- lua: &'lua Lua,
- source: &'a [u8],
- name: Option<CString>,
- env: Result<Option<Value<'lua>>>,
- mode: Option<ChunkMode>,
-}
-
-/// Represents chunk mode (text or binary).
-#[derive(Clone, Copy, Debug)]
-pub enum ChunkMode {
- Text,
- Binary,
-}
-
-/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
-///
-/// [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) -> &[u8];
-
- /// Returns optional chunk name
- fn name(&self) -> Option<CString> {
- None
- }
-
- /// Returns optional chunk [environment]
- ///
- /// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2
- fn env(&self, _lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
- Ok(None)
- }
-
- /// Returns optional chunk mode (text or binary)
- fn mode(&self) -> Option<ChunkMode> {
- None
- }
-}
-
-impl<'lua, 'a> Chunk<'lua, 'a> {
- /// Sets the name of this chunk, which results in more informative error traces.
- pub fn set_name<S: AsRef<[u8]> + ?Sized>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
- let name =
- CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
- from: "&str",
- to: "string",
- message: Some(e.to_string()),
- })?;
- self.name = Some(name);
- Ok(self)
- }
-
- /// Sets the first upvalue (`_ENV`) of the loaded chunk to the given value.
- ///
- /// Lua main chunks always have exactly one upvalue, and this upvalue is used as the `_ENV`
- /// variable inside the chunk. By default this value is set to the global environment.
- ///
- /// Calling this method changes the `_ENV` upvalue to the value provided, and variables inside
- /// the chunk will refer to the given environment rather than the global one.
- ///
- /// 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<V: ToLua<'lua>>(mut self, env: V) -> Result<Chunk<'lua, 'a>> {
- // Prefer to propagate errors here and wrap to `Ok`
- self.env = Ok(Some(env.to_lua(self.lua)?));
- Ok(self)
- }
-
- /// Sets whether the chunk is text or binary (autodetected by default).
- ///
- /// Lua does not check the consistency of binary chunks, therefore this mode is allowed only
- /// for instances created with [`Lua::unsafe_new`].
- ///
- /// [`Lua::unsafe_new`]: crate::Lua::unsafe_new
- pub fn set_mode(mut self, mode: ChunkMode) -> Chunk<'lua, 'a> {
- self.mode = Some(mode);
- self
- }
-
- /// Execute this chunk of code.
- ///
- /// This is equivalent to calling the chunk function with no arguments and no return values.
- pub fn exec(self) -> Result<()> {
- self.call(())?;
- Ok(())
- }
-
- /// Asynchronously execute this chunk of code.
- ///
- /// See [`exec`] for more details.
- ///
- /// Requires `feature = "async"`
- ///
- /// [`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,
- {
- self.call_async(())
- }
-
- /// Evaluate the chunk as either an expression or block.
- ///
- /// If the chunk can be parsed as an expression, this loads and executes the chunk and returns
- /// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
- /// and this is equivalent to calling `exec`.
- pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
- // Bytecode is always interpreted as a statement.
- // For source code, 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.
- if self.source[0] < b'\n' {
- self.call(())
- } else if let Ok(function) = self.lua.load_chunk(
- &self.expression_source(),
- self.name.as_ref(),
- self.env()?,
- self.mode,
- ) {
- function.call(())
- } else {
- self.call(())
- }
- }
-
- /// Asynchronously evaluate the chunk as either an expression or block.
- ///
- /// See [`eval`] for more details.
- ///
- /// Requires `feature = "async"`
- ///
- /// [`eval`]: #method.eval
- #[cfg(feature = "async")]
- #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
- pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result<R>>
- where
- 'lua: 'fut,
- R: FromLuaMulti<'lua> + 'fut,
- {
- if self.source[0] < b'\n' {
- self.call_async(())
- } else if let Ok(function) = self.lua.load_chunk(
- &self.expression_source(),
- self.name.as_ref(),
- match self.env() {
- Ok(env) => env,
- Err(e) => return Box::pin(future::err(e)),
- },
- self.mode,
- ) {
- function.call_async(())
- } else {
- self.call_async(())
- }
- }
-
- /// Load the chunk function and call it with the given arguments.
- ///
- /// This is equivalent to `into_function` and calling the resulting function.
- pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(self, args: A) -> Result<R> {
- self.into_function()?.call(args)
- }
-
- /// Load the chunk function and asynchronously call it with the given arguments.
- ///
- /// See [`call`] for more details.
- ///
- /// Requires `feature = "async"`
- ///
- /// [`call`]: #method.call
- #[cfg(feature = "async")]
- #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
- pub fn call_async<'fut, A, R>(self, args: A) -> LocalBoxFuture<'fut, Result<R>>
- where
- 'lua: 'fut,
- A: ToLuaMulti<'lua>,
- R: FromLuaMulti<'lua> + 'fut,
- {
- match self.into_function() {
- Ok(func) => func.call_async(args),
- Err(e) => Box::pin(future::err(e)),
- }
- }
-
- /// Load this chunk into a regular `Function`.
- ///
- /// This simply compiles the chunk without actually executing it.
- pub fn into_function(self) -> Result<Function<'lua>> {
- self.lua
- .load_chunk(self.source, self.name.as_ref(), self.env()?, self.mode)
- }
-
- fn env(&self) -> Result<Option<Value<'lua>>> {
- self.env.clone()
- }
-
- fn expression_source(&self) -> Vec<u8> {
- let mut buf = Vec::with_capacity(b"return ".len() + self.source.len());
- buf.extend(b"return ");
- buf.extend(self.source);
- buf
- }
-}
-
-impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
- fn source(&self) -> &[u8] {
- self.as_ref()
- }
-}
-
// Creates required entries in the metatable cache (see `util::METATABLE_CACHE`)
pub(crate) fn init_metatable_cache(cache: &mut FxHashMap<TypeId, u8>) {
cache.insert(TypeId::of::<Arc<UnsafeCell<ExtraData>>>(), 0);