use std::{env, fs, io, path::Path, sync::LazyLock};
use crate::{Assembly, Compiler, NativeSys, UiuaResult};
const STAND_DATA_SIGNATURE: &[u8] = b"Uiua standalone";
pub fn build_exe(root: &Path) -> UiuaResult<Vec<u8>> {
let asm = Compiler::with_backend(NativeSys).load_file(root)?.finish();
let asm_bytes = asm.to_uasm().into_bytes();
let mut bytes = env::current_exe()
.and_then(fs::read)
.unwrap_or_else(|e| panic!("Unable to read current exe: {e}"));
bytes.extend_from_slice(&asm_bytes);
bytes.extend((asm_bytes.len() as u64).to_le_bytes());
bytes.extend(STAND_DATA_SIGNATURE);
Ok(bytes)
}
fn load_asm() -> io::Result<Option<Assembly>> {
let bytes = fs::read(env::current_exe()?)?;
let Some(bytes) = bytes.strip_suffix(STAND_DATA_SIGNATURE) else {
return Ok(None);
};
let (bytes, len_bytes) = bytes.split_at(bytes.len() - 8);
let asm_len = u64::from_le_bytes(len_bytes.try_into().unwrap());
let start = bytes.len() - asm_len as usize;
let uasm: String = std::str::from_utf8(&bytes[start..]).unwrap().to_string();
let asm = Assembly::from_uasm(&uasm).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Failed to deserialize assembly: {e}\n\nuasm text:\n{uasm}"),
)
})?;
Ok(Some(asm))
}
pub static STAND_ASM: LazyLock<Option<Assembly>> =
LazyLock::new(|| load_asm().unwrap_or_else(|e| panic!("{e}")));