use std::{borrow::Cow, ptr::NonNull};
use from_singleton::*;
use pelite::pe64::{Pe, Rva};
use thiserror::Error;
use crate::Program;
#[derive(Error, Debug)]
pub enum InstanceError {
#[error("Static object not found")]
NotFound,
#[error("Static object not initialized")]
Null,
}
pub type InstanceResult<T> = Result<T, InstanceError>;
pub trait FromStatic {
fn name() -> Cow<'static, str>;
unsafe fn instance() -> InstanceResult<&'static mut Self>;
}
impl<T: FromSingleton> FromStatic for T {
fn name() -> Cow<'static, str> {
<Self as FromSingleton>::name()
}
unsafe fn instance() -> InstanceResult<&'static mut T> {
address_of::<T>()
.map(|mut ptr| unsafe { ptr.as_mut() })
.ok_or(InstanceError::NotFound)
}
}
pub unsafe fn load_static_direct<T: FromStatic>(rva: Rva) -> InstanceResult<&'static mut T> {
let target = Program::current()
.rva_to_va(rva)
.map_err(|_| InstanceError::NotFound)? as *mut T;
unsafe { target.as_mut().ok_or(InstanceError::Null) }
}
pub unsafe fn load_static_indirect<T: FromStatic>(rva: Rva) -> InstanceResult<&'static mut T> {
let target = Program::current()
.rva_to_va(rva)
.map_err(|_| InstanceError::NotFound)? as *mut Option<NonNull<T>>;
unsafe {
target
.as_mut()
.and_then(|opt| opt.as_mut())
.map(|nn| nn.as_mut())
.ok_or(InstanceError::Null)
}
}