#[cfg(target_os = "psp")]
use crate::sys::SceStubLibraryEntry;
#[cfg(target_os = "psp")]
macro_rules! link_section_concat {
($(#[link_section = $section:expr] $item:item)*) => {
$(
#[link_section = $section]
$item
)*
}
}
#[cfg(target_os = "psp")]
#[derive(Copy, Clone)]
pub(crate) struct Stub {
#[allow(dead_code)]
pub(crate) lib_addr: &'static SceStubLibraryEntry,
#[allow(dead_code)]
pub(crate) nid_addr: &'static u32,
}
#[cfg(target_os = "psp")]
pub const fn lib_name_bytes_len(name: &str) -> usize {
let name_len = name.as_bytes().len();
return name_len + (4 - name_len % 4);
}
#[cfg(target_os = "psp")]
pub const fn lib_name_bytes<const T: usize>(name: &str) -> [u8; T] {
let mut buf = [0; T];
let name_bytes = name.as_bytes();
let mut i = 0;
while i < name_bytes.len() {
buf[i] = name_bytes[i];
i += 1;
}
buf
}
macro_rules! psp_extern {
(__BODY $name:ident ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?) => {{
paste! {
extern "C" {
pub fn [< __ $name _stub >]($($arg : $arg_ty),*) $(-> $ret)?;
}
let func = [< __ $name _stub >];
func($($arg),*)
}
}};
(__BODY $abi:ident $name:ident ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?) => {{
type Func = unsafe extern "C" fn($($arg : $arg_ty),*) $(-> $ret)?;
paste! {
extern "C" {
pub fn [< __ $name _stub >]($($arg : $arg_ty),*) $(-> $ret)?;
}
let func = [< __ $name _stub >] as Func;
core::mem::transmute($abi(
$(core::mem::transmute($arg)),*,
core::mem::transmute(func),
))
}
}};
(
#![name = $lib_name:expr]
#![flags = $lib_flags:expr]
#![version = ($lib_major_version:expr, $lib_minor_version:expr)]
$(
#[psp($nid:expr $(, $abi:ident)?)]
$(#[$attr:meta])*
pub fn $name:ident($($arg:ident : $arg_ty:ty),* $(,)?)
$(-> $ret:ty)?;
)*
) => {
paste! {
#[allow(non_snake_case)]
mod [< __ $lib_name _mod >] {
#[allow(unused)]
use super::*;
#[cfg(target_os = "psp")]
link_section_concat! {
#[link_section = concat!(".rodata.sceResident.", $lib_name)]
#[allow(non_upper_case_globals)]
static [< __ $lib_name _RESIDENT >] : [u8; $crate::sys::macros::lib_name_bytes_len($lib_name)] = $crate::sys::macros::lib_name_bytes($lib_name);
#[link_section = concat!(".rodata.sceNid.", $lib_name)]
#[allow(non_upper_case_globals)]
static [< __ $lib_name _NID_START >] : () = ();
#[link_section = concat!(".sceStub.text.", $lib_name)]
#[allow(non_upper_case_globals)]
static [< __ $lib_name _STUB_START >] : () = ();
#[link_section = concat!(".lib.stub.entry.", $lib_name)]
#[allow(non_upper_case_globals)]
static [< __ $lib_name _STUB >] : $crate::sys::SceStubLibraryEntry = $crate::sys::SceStubLibraryEntry {
name: paste! { & [< __ $lib_name _RESIDENT >] [0] },
version: [$lib_minor_version, $lib_major_version],
flags: $lib_flags,
len: 5,
v_stub_count: 0,
stub_count: 0,
nid_table: & [< __ $lib_name _NID_START >] as *const () as *const _,
stub_table: & [< __ $lib_name _STUB_START >] as *const () as *const _,
};
}
$(
#[allow(unused)]
use super::*;
#[cfg(target_os = "psp")]
link_section_concat! {
#[link_section = concat!(
".rodata.sceNid.", $lib_name,
".", stringify!($name)
)]
#[allow(non_upper_case_globals)]
static [< __ $name _NID >]: u32 = $nid;
#[link_section = concat!(
".sceStub.text.", $lib_name,
".", stringify!($name)
)]
#[no_mangle]
#[allow(non_upper_case_globals)]
static [< __ $name _stub >]: $crate::sys::macros::Stub = $crate::sys::macros::Stub {
lib_addr: &[< __ $lib_name _STUB >],
nid_addr: &[< __ $name _NID >],
};
}
$(#[$attr])*
#[allow(non_snake_case, clippy::missing_safety_doc)]
#[no_mangle]
pub unsafe extern fn $name($($arg : $arg_ty),*) $(-> $ret)? {
#[cfg(target_os = "psp")]
{
psp_extern!(
__BODY $($abi)?
$name($($arg : $arg_ty),*) $(-> $ret)?
)
}
#[cfg(not(target_os = "psp"))]
{
$(let _arg = $arg;)*
$(let _abi = $abi;)?
panic!("tried to call PSP system function on non-PSP target");
}
}
)*
}
}
paste! {
$(
pub use self :: [< __ $lib_name _mod >] :: $name;
)*
}
}
}