Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some methods for build use #352

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ Cargo.lock
.vscode/
.DS_Store
.stignore

*.bin
2 changes: 1 addition & 1 deletion src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,4 +524,4 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
buf.extend(source);
buf
}
}
}
137 changes: 137 additions & 0 deletions src/lua.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3192,6 +3192,143 @@ impl Lua {
pub(crate) fn clone(&self) -> Arc<LuaInner> {
Arc::clone(&self.0)
}

/// Compile all the files to bytecode under a directory, save as `*.bin`
///
/// It designs for build script, so there will be no error return.
///
/// It will automatically print cargo:rerun-if-changed=*
///
/// In release mode, it may not save all the debug information, see also [`Function::dump()`]
///
/// # Examples
///
/// ```
/// use mlua::prelude::*;
/// fn main(){
/// let lua = Lua::new();
///
/// lua.compile_single("./tests/scripts/a.lua")
/// .compile_single("./tests/scripts/b.lua");
/// }
/// ```
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[track_caller]
#[inline]
pub fn compile_single(&self, path: impl AsRef<std::path::Path>) -> &Self {
use std::fs;
use std::path::PathBuf;

let path = path.as_ref();

println!("cargo:rerun-if-changed={}", path.display());

let bytes = fs::read(path).unwrap_or_else(|err| {
panic!(
"Error caused while reading the source file\nAt Path: {}\nCaused by:\n\t{:?}",
path.display(),
err
)
});

let strip;
#[cfg(debug_assertions)]
{
strip = false;
}
#[cfg(not(debug_assertions))]
{
strip = true;
}

let bytecode = self.load(&bytes).into_function().unwrap_or_else(|err|{
panic!(
"Error caused while converting chunk into function\nAt Path: {}\nCaused by:\n\t{:?}",
path.display(),
err
)
}).dump(strip);

let mut path = PathBuf::from(path);
path.set_extension("bin");

fs::write(&path, bytecode).unwrap_or_else(|err| {
panic!(
"Error caused while writing the bytecode\nAt Path: {}\nCaused by:\n\t{:?}",
path.display(),
err
)
});

self
}

/// Compile all the files with the extension `lua` to bytecode under a directory, save as `*.bin`
///
/// It is designed for build script, so there will be no error return.
///
/// It automatically print cargo:rerun-if-changed=* of each script file
///
/// It calls [`Lua::compile_single()`] on every file
///
/// # Examples
///
/// ```
/// use mlua::prelude::*;
/// fn main(){
/// let lua = Lua::new();
///
/// lua.compile_directory("./tests/scripts")
/// .compile_directory("./tests/scripts");
/// }
/// ```
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[track_caller]
pub fn compile_directory(&self, path: impl AsRef<std::path::Path>) -> &Self {
use std::fs;
use std::path::{Path, PathBuf};
#[track_caller]
fn all_files(path: impl AsRef<Path>) -> std::io::Result<Vec<PathBuf>> {
// here use a BFS to traversal all the files under a directory
let mut stk = vec![path.as_ref().to_path_buf()];
let mut ans = Vec::new();
while let Some(path) = stk.pop() {
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
stk.push(path);
} else {
if let Some(exe) = path.extension() {
if exe == "lua" {
ans.push(path);
}
}
}
}
}

Ok(ans)
}

let path = path.as_ref();

let files = all_files(path).unwrap_or_else(|err| {
panic!(
"Error caused while traversal the directory\nAt Path: {}\nCaused by:\n\t{:?}",
path.display(),
err
)
});

for path in files {
self.compile_single(path);
}

self
}
}

impl LuaInner {
Expand Down
60 changes: 60 additions & 0 deletions tests/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::io;

use mlua::{Lua, Result};

use std::path::{Path, PathBuf};

#[test]
#[cfg(not(target_arch = "wasm32"))]
fn test_chunk_path() -> Result<()> {
Expand All @@ -28,6 +30,64 @@ fn test_chunk_path() -> Result<()> {
Ok(())
}

#[test]
#[cfg(not(feature = "luau"))]
fn test_compile() {
let lua = Lua::new();

let work_dir = Path::new("./tests/scripts/compile/");

let assert = || {
assert_eq!(
lua.load(fs::read(work_dir.join("a.bin")).unwrap())
.eval::<String>()
.unwrap(),
"Helloworld".to_string()
);

assert_eq!(
lua.load(fs::read(work_dir.join("b.bin")).unwrap())
.eval::<String>()
.unwrap(),
"Helloworld".to_string()
);
};

lua.compile_single(work_dir.join("a.lua"))
.compile_single(work_dir.join("b.lua"));

assert();

// remove them to make sure the code above don't influence them test below
fs::remove_file(work_dir.join("a.bin")).unwrap();
fs::remove_file(work_dir.join("b.bin")).unwrap();

lua.compile_directory(work_dir);

assert();
}

#[test]
#[cfg(not(feature = "luau"))]
fn multi_file_def() {
let lua = Lua::new();

let work_dir = Path::new("./tests/scripts/multi_file_def");

lua.compile_directory(work_dir);

lua.load(fs::read(work_dir.join("c.bin")).unwrap())
.exec()
.unwrap();

let value = lua
.load(fs::read(work_dir.join("d.bin")).unwrap())
.eval::<String>()
.unwrap();

assert_eq!(value.as_str(), "Hello world !");
}

#[test]
#[cfg(feature = "macros")]
fn test_chunk_macro() -> Result<()> {
Expand Down
1 change: 1 addition & 0 deletions tests/scripts/compile/a.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return "Hello" .. "world"
1 change: 1 addition & 0 deletions tests/scripts/compile/b.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return "Hello" .. "world"
1 change: 1 addition & 0 deletions tests/scripts/compile/info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Belong to [test_compile()](../../chunk.rs)
1 change: 1 addition & 0 deletions tests/scripts/multi_file_def/c.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello = "Hello world !"
1 change: 1 addition & 0 deletions tests/scripts/multi_file_def/d.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return hello;
1 change: 1 addition & 0 deletions tests/scripts/multi_file_def/info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Belong to [multi_file_def()](../../chunk.rs)