mirror of
https://github.com/lune-org/lune.git
synced 2025-04-11 22:10:53 +01:00
refactor: move most shared logic to executor.rs
This commit is contained in:
parent
94fd549a65
commit
55fe033f21
2 changed files with 164 additions and 163 deletions
162
src/cli/build.rs
162
src/cli/build.rs
|
@ -1,6 +1,5 @@
|
||||||
use console::Style;
|
use console::Style;
|
||||||
use num_traits::{FromBytes, ToBytes};
|
use std::{env, path::Path, process::ExitCode};
|
||||||
use std::{env, ops::ControlFlow, path::Path, process::ExitCode};
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::{self, OpenOptions},
|
fs::{self, OpenOptions},
|
||||||
io::AsyncWriteExt,
|
io::AsyncWriteExt,
|
||||||
|
@ -9,164 +8,7 @@ use tokio::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use mlua::Compiler as LuaCompiler;
|
use mlua::Compiler as LuaCompiler;
|
||||||
|
|
||||||
// The signature which separates indicates the presence of bytecode to execute
|
use crate::executor::{MetaChunk, MAGIC};
|
||||||
// If a binary contains this magic signature as the last 8 bytes, that must mean
|
|
||||||
// it is a standalone binary
|
|
||||||
pub const MAGIC: &[u8; 8] = b"cr3sc3nt";
|
|
||||||
|
|
||||||
/// Utility struct to parse and generate bytes to the META chunk of standalone binaries.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MetaChunk {
|
|
||||||
/// Compiled lua bytecode of the entrypoint script.
|
|
||||||
pub bytecode: Vec<u8>,
|
|
||||||
/// Offset to the the beginning of the bytecode from the start of the lune binary.
|
|
||||||
pub bytecode_offset: Option<u64>,
|
|
||||||
/// Number of files present, currently unused. **For future use**.
|
|
||||||
pub file_count: Option<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MetaChunk {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
bytecode: Vec::new(),
|
|
||||||
bytecode_offset: None,
|
|
||||||
file_count: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_bytecode(&mut self, bytecode: Vec<u8>) -> Self {
|
|
||||||
self.bytecode = bytecode;
|
|
||||||
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_bytecode_offset(&mut self, offset: u64) -> Self {
|
|
||||||
self.bytecode_offset = Some(offset);
|
|
||||||
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_file_count(&mut self, count: u64) -> Self {
|
|
||||||
self.file_count = Some(count);
|
|
||||||
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self, endianness: &str) -> Vec<u8> {
|
|
||||||
match endianness {
|
|
||||||
"big" => self.to_be_bytes(),
|
|
||||||
"little" => self.to_le_bytes(),
|
|
||||||
&_ => panic!("unexpected endianness"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8], int_handler: fn([u8; 8]) -> u64) -> Result<Self> {
|
|
||||||
let mut bytecode_offset = 0;
|
|
||||||
let mut bytecode_size = 0;
|
|
||||||
|
|
||||||
// standalone binary structure (reversed, 8 bytes per field)
|
|
||||||
// [0] => magic signature
|
|
||||||
// ----------------
|
|
||||||
// -- META Chunk --
|
|
||||||
// [1] => file count
|
|
||||||
// [2] => bytecode size
|
|
||||||
// [3] => bytecode offset
|
|
||||||
// ----------------
|
|
||||||
// -- MISC Chunk --
|
|
||||||
// [4..n] => bytecode (variable size)
|
|
||||||
// ----------------
|
|
||||||
// NOTE: All integers are 8 byte, padded, unsigned & 64 bit (u64's).
|
|
||||||
|
|
||||||
// The rchunks will have unequally sized sections in the beginning
|
|
||||||
// but that doesn't matter to us because we don't need anything past the
|
|
||||||
// middle chunks where the bytecode is stored
|
|
||||||
bytes
|
|
||||||
.rchunks(MAGIC.len())
|
|
||||||
.enumerate()
|
|
||||||
.try_for_each(|(idx, chunk)| {
|
|
||||||
if bytecode_offset != 0 && bytecode_size != 0 {
|
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if idx == 0 && chunk != MAGIC {
|
|
||||||
// Binary is guaranteed to be standalone, we've confirmed this before
|
|
||||||
unreachable!("expected proper magic signature for standalone binary")
|
|
||||||
}
|
|
||||||
|
|
||||||
if idx == 3 {
|
|
||||||
bytecode_offset = int_handler(chunk.try_into().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if idx == 2 {
|
|
||||||
bytecode_size = int_handler(chunk.try_into().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
});
|
|
||||||
|
|
||||||
println!("size: {}", bytecode_size);
|
|
||||||
println!("offset: {}", bytecode_offset);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
bytecode: bytes[usize::try_from(bytecode_offset)?
|
|
||||||
..usize::try_from(bytecode_offset + bytecode_size)?]
|
|
||||||
.to_vec(),
|
|
||||||
bytecode_offset: Some(bytecode_offset),
|
|
||||||
file_count: Some(1),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MetaChunk {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
bytecode: Vec::new(),
|
|
||||||
bytecode_offset: Some(0),
|
|
||||||
file_count: Some(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToBytes for MetaChunk {
|
|
||||||
type Bytes = Vec<u8>;
|
|
||||||
|
|
||||||
fn to_be_bytes(&self) -> Self::Bytes {
|
|
||||||
// We start with the bytecode offset as the first field already filled in
|
|
||||||
let mut tmp = self.bytecode_offset.unwrap().to_be_bytes().to_vec();
|
|
||||||
|
|
||||||
// NOTE: The order of the fields here are reversed, which is on purpose
|
|
||||||
tmp.extend(self.bytecode.len().to_be_bytes());
|
|
||||||
tmp.extend(self.file_count.unwrap().to_be_bytes());
|
|
||||||
|
|
||||||
tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_le_bytes(&self) -> Self::Bytes {
|
|
||||||
// We start with the bytecode offset as the first field already filled in
|
|
||||||
let mut tmp = self.bytecode_offset.unwrap().to_le_bytes().to_vec();
|
|
||||||
|
|
||||||
// NOTE: The order of the fields here are reversed, which is on purpose
|
|
||||||
tmp.extend(self.bytecode.len().to_le_bytes());
|
|
||||||
tmp.extend(self.file_count.unwrap().to_le_bytes());
|
|
||||||
|
|
||||||
println!("size: {}", self.bytecode.len());
|
|
||||||
println!("offset: {:?}", self.bytecode_offset);
|
|
||||||
|
|
||||||
tmp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBytes for MetaChunk {
|
|
||||||
type Bytes = Vec<u8>;
|
|
||||||
|
|
||||||
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
|
|
||||||
Self::from_bytes(bytes, u64::from_be_bytes).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
|
|
||||||
Self::from_bytes(bytes, u64::from_le_bytes).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
||||||
|
|
165
src/executor.rs
165
src/executor.rs
|
@ -1,12 +1,171 @@
|
||||||
use std::{env, process::ExitCode};
|
use std::{env, ops::ControlFlow, process::ExitCode};
|
||||||
|
|
||||||
use crate::cli::build::{MetaChunk, MAGIC};
|
|
||||||
use lune::Lune;
|
use lune::Lune;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use num_traits::FromBytes;
|
use num_traits::{FromBytes, ToBytes};
|
||||||
use tokio::fs::read as read_to_vec;
|
use tokio::fs::read as read_to_vec;
|
||||||
|
|
||||||
|
// The signature which separates indicates the presence of bytecode to execute
|
||||||
|
// If a binary contains this magic signature as the last 8 bytes, that must mean
|
||||||
|
// it is a standalone binary
|
||||||
|
pub const MAGIC: &[u8; 8] = b"cr3sc3nt";
|
||||||
|
|
||||||
|
/// Utility struct to parse and generate bytes to the META chunk of standalone binaries.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MetaChunk {
|
||||||
|
/// Compiled lua bytecode of the entrypoint script.
|
||||||
|
pub bytecode: Vec<u8>,
|
||||||
|
/// Offset to the the beginning of the bytecode from the start of the lune binary.
|
||||||
|
pub bytecode_offset: Option<u64>,
|
||||||
|
/// Number of files present, currently unused. **For future use**.
|
||||||
|
pub file_count: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaChunk {
|
||||||
|
/// Creates an emtpy `MetaChunk` instance.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bytecode: Vec::new(),
|
||||||
|
bytecode_offset: None,
|
||||||
|
file_count: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builder method to include the bytecode, **mandatory** before build.
|
||||||
|
pub fn with_bytecode(&mut self, bytecode: Vec<u8>) -> Self {
|
||||||
|
self.bytecode = bytecode;
|
||||||
|
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builder method to include the bytecode offset, **mandatory** before build.
|
||||||
|
pub fn with_bytecode_offset(&mut self, offset: u64) -> Self {
|
||||||
|
self.bytecode_offset = Some(offset);
|
||||||
|
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builder method to include the file count, **mandatory** before build.
|
||||||
|
|
||||||
|
pub fn with_file_count(&mut self, count: u64) -> Self {
|
||||||
|
self.file_count = Some(count);
|
||||||
|
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds the final `Vec` of bytes, based on the endianness specified.
|
||||||
|
pub fn build(self, endianness: &str) -> Vec<u8> {
|
||||||
|
match endianness {
|
||||||
|
"big" => self.to_be_bytes(),
|
||||||
|
"little" => self.to_le_bytes(),
|
||||||
|
&_ => panic!("unexpected endianness"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal method which implements endian independent bytecode discovery logic.
|
||||||
|
fn from_bytes(bytes: &[u8], int_handler: fn([u8; 8]) -> u64) -> Result<Self> {
|
||||||
|
let mut bytecode_offset = 0;
|
||||||
|
let mut bytecode_size = 0;
|
||||||
|
|
||||||
|
// standalone binary structure (reversed, 8 bytes per field)
|
||||||
|
// [0] => magic signature
|
||||||
|
// ----------------
|
||||||
|
// -- META Chunk --
|
||||||
|
// [1] => file count
|
||||||
|
// [2] => bytecode size
|
||||||
|
// [3] => bytecode offset
|
||||||
|
// ----------------
|
||||||
|
// -- MISC Chunk --
|
||||||
|
// [4..n] => bytecode (variable size)
|
||||||
|
// ----------------
|
||||||
|
// NOTE: All integers are 8 byte, padded, unsigned & 64 bit (u64's).
|
||||||
|
|
||||||
|
// The rchunks will have unequally sized sections in the beginning
|
||||||
|
// but that doesn't matter to us because we don't need anything past the
|
||||||
|
// middle chunks where the bytecode is stored
|
||||||
|
bytes
|
||||||
|
.rchunks(MAGIC.len())
|
||||||
|
.enumerate()
|
||||||
|
.try_for_each(|(idx, chunk)| {
|
||||||
|
if bytecode_offset != 0 && bytecode_size != 0 {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx == 0 && chunk != MAGIC {
|
||||||
|
// Binary is guaranteed to be standalone, we've confirmed this before
|
||||||
|
unreachable!("expected proper magic signature for standalone binary")
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx == 3 {
|
||||||
|
bytecode_offset = int_handler(chunk.try_into().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx == 2 {
|
||||||
|
bytecode_size = int_handler(chunk.try_into().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
bytecode: bytes[usize::try_from(bytecode_offset)?
|
||||||
|
..usize::try_from(bytecode_offset + bytecode_size)?]
|
||||||
|
.to_vec(),
|
||||||
|
bytecode_offset: Some(bytecode_offset),
|
||||||
|
file_count: Some(1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MetaChunk {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
bytecode: Vec::new(),
|
||||||
|
bytecode_offset: Some(0),
|
||||||
|
file_count: Some(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToBytes for MetaChunk {
|
||||||
|
type Bytes = Vec<u8>;
|
||||||
|
|
||||||
|
fn to_be_bytes(&self) -> Self::Bytes {
|
||||||
|
// We start with the bytecode offset as the first field already filled in
|
||||||
|
let mut tmp = self.bytecode_offset.unwrap().to_be_bytes().to_vec();
|
||||||
|
|
||||||
|
// NOTE: The order of the fields here are reversed, which is on purpose
|
||||||
|
tmp.extend(self.bytecode.len().to_be_bytes());
|
||||||
|
tmp.extend(self.file_count.unwrap().to_be_bytes());
|
||||||
|
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_le_bytes(&self) -> Self::Bytes {
|
||||||
|
// We start with the bytecode offset as the first field already filled in
|
||||||
|
let mut tmp = self.bytecode_offset.unwrap().to_le_bytes().to_vec();
|
||||||
|
|
||||||
|
// NOTE: The order of the fields here are reversed, which is on purpose
|
||||||
|
tmp.extend(self.bytecode.len().to_le_bytes());
|
||||||
|
tmp.extend(self.file_count.unwrap().to_le_bytes());
|
||||||
|
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromBytes for MetaChunk {
|
||||||
|
type Bytes = Vec<u8>;
|
||||||
|
|
||||||
|
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
|
||||||
|
Self::from_bytes(bytes, u64::from_be_bytes).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
|
||||||
|
Self::from_bytes(bytes, u64::from_le_bytes).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns information about whether the execution environment is standalone
|
Returns information about whether the execution environment is standalone
|
||||||
or not, the standalone binary signature, and the contents of the binary.
|
or not, the standalone binary signature, and the contents of the binary.
|
||||||
|
|
Loading…
Add table
Reference in a new issue