use std::{ env::{self, current_dir, set_current_dir}, ffi::CString, fs, io::Write, panic, path::PathBuf, process::Command, ptr, sync::{ Mutex, atomic::{AtomicBool, Ordering}, }, }; static RELOAD: AtomicBool = AtomicBool::new(false); fn exe_path() -> String { env::current_exe() .unwrap() .to_string_lossy() .replace(" (deleted)", "") } fn cargo_path() -> Option { let exe = exe_path(); let parts: Vec<_> = exe.split('/').collect(); for i in (0..parts.len()).rev() { let base_dir = format!("/{}", parts[0..i].join("/")); let toml_path = format!("/{base_dir}/Cargo.toml"); if fs::exists(toml_path).unwrap() { return Some(base_dir); } } None } pub fn begin_reload() { let Some(cargo_path) = cargo_path() else { return; }; set_current_dir(cargo_path).unwrap(); let Ok(status) = Command::new("cargo").arg("build").status() else { return; }; if !status.success() { return; } RELOAD.store(true, Ordering::SeqCst); panic::resume_unwind(Box::new(42)); } /// ONLY TO BE CALLED FROM MAIN WHEN NOT A SINGLE RESOURCE IS HELD pub unsafe fn continue_reload() { if !RELOAD.load(Ordering::SeqCst) { return; } eprintln!("reloading..."); let _ = std::io::stdout().lock().flush(); unsafe { exec() } eprintln!("exec failed."); } unsafe fn exec() { // path to this executable let exe = env::current_exe() .unwrap() .to_string_lossy() .replace(" (deleted)", ""); let exe_c = CString::new(exe).unwrap(); // argv let args: Vec = env::args().map(|a| CString::new(a).unwrap()).collect(); let mut argv: Vec<*const libc::c_char> = args.iter().map(|a| a.as_ptr()).collect(); argv.push(ptr::null()); unsafe { libc::execv(exe_c.as_ptr(), argv.as_ptr()); } }