use crate::error::{VZError, VZResult};
use crate::ffi::{get_class, nsurl_file_path, release};
use crate::{msg_send, msg_send_void};
use objc2::runtime::AnyObject;
use std::path::Path;
pub trait BootLoader {
fn as_ptr(&self) -> *mut AnyObject;
}
pub struct LinuxBootLoader {
inner: *mut AnyObject,
}
unsafe impl Send for LinuxBootLoader {}
impl LinuxBootLoader {
pub fn new(kernel_path: impl AsRef<Path>) -> VZResult<Self> {
let path = kernel_path.as_ref();
if !path.exists() {
return Err(VZError::NotFound(path.display().to_string()));
}
let path_str = path.to_string_lossy();
unsafe {
let cls = get_class("VZLinuxBootLoader").ok_or_else(|| VZError::Internal {
code: -1,
message: "VZLinuxBootLoader class not found".into(),
})?;
let kernel_url = nsurl_file_path(&path_str);
let alloc = msg_send!(cls, alloc);
let obj = msg_send!(alloc, initWithKernelURL: kernel_url);
if obj.is_null() {
return Err(VZError::InvalidConfiguration(format!(
"Failed to create boot loader for kernel: {path_str}"
)));
}
Ok(Self { inner: obj })
}
}
pub fn set_initial_ramdisk(&mut self, path: impl AsRef<Path>) -> &mut Self {
let path = path.as_ref();
if path.exists() {
let path_str = path.to_string_lossy();
unsafe {
let url = nsurl_file_path(&path_str);
msg_send_void!(self.inner, setInitialRamdiskURL: url);
}
}
self
}
pub fn set_command_line(&mut self, cmdline: &str) -> &mut Self {
unsafe {
let s = crate::ffi::nsstring(cmdline);
msg_send_void!(self.inner, setCommandLine: s);
}
self
}
}
impl BootLoader for LinuxBootLoader {
fn as_ptr(&self) -> *mut AnyObject {
self.inner
}
}
impl Drop for LinuxBootLoader {
fn drop(&mut self) {
if !self.inner.is_null() {
release(self.inner);
}
}
}